blob: ec7960440369e5f2d895830bfd7e3af9219af6c7 [file] [log] [blame]
Jeff Thompson86b6d642013-10-17 15:01:56 -07001// (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 NDNBOOST_IOSTREAMS_DETAIL_DIRECT_STREAMBUF_HPP_INCLUDED
9#define NDNBOOST_IOSTREAMS_DETAIL_DIRECT_STREAMBUF_HPP_INCLUDED
10
11#if defined(_MSC_VER) && (_MSC_VER >= 1020)
12# pragma once
13#endif
14
15#include <ndnboost/assert.hpp>
16#include <cstddef>
17#include <typeinfo>
18#include <utility> // pair.
19#include <ndnboost/config.hpp> // NDNBOOST_DEDUCED_TYPENAME,
20#include <ndnboost/iostreams/detail/char_traits.hpp> // member template friends.
21#include <ndnboost/iostreams/detail/config/wide_streams.hpp>
22#include <ndnboost/iostreams/detail/error.hpp>
23#include <ndnboost/iostreams/detail/execute.hpp>
24#include <ndnboost/iostreams/detail/functional.hpp>
25#include <ndnboost/iostreams/detail/ios.hpp>
26#include <ndnboost/iostreams/detail/optional.hpp>
27#include <ndnboost/iostreams/detail/streambuf.hpp>
28#include <ndnboost/iostreams/detail/streambuf/linked_streambuf.hpp>
29#include <ndnboost/iostreams/operations.hpp>
30#include <ndnboost/iostreams/positioning.hpp>
31#include <ndnboost/iostreams/traits.hpp>
32#include <ndnboost/throw_exception.hpp>
33
34// Must come last.
35#include <ndnboost/iostreams/detail/config/disable_warnings.hpp> // MSVC.
36
37namespace ndnboost { namespace iostreams {
38
39namespace detail {
40
41template< typename T,
42 typename Tr =
43 NDNBOOST_IOSTREAMS_CHAR_TRAITS(
44 NDNBOOST_DEDUCED_TYPENAME char_type_of<T>::type
45 ) >
46class direct_streambuf
47 : public linked_streambuf<NDNBOOST_DEDUCED_TYPENAME char_type_of<T>::type, Tr>
48{
49public:
50 typedef typename char_type_of<T>::type char_type;
51 NDNBOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
52private:
53 typedef linked_streambuf<char_type, traits_type> base_type;
54 typedef typename category_of<T>::type category;
55 typedef NDNBOOST_IOSTREAMS_BASIC_STREAMBUF(
56 char_type, traits_type
57 ) streambuf_type;
58public: // stream needs access.
59 void open(const T& t, std::streamsize buffer_size,
60 std::streamsize pback_size);
61 bool is_open() const;
62 void close();
63 bool auto_close() const { return auto_close_; }
64 void set_auto_close(bool close) { auto_close_ = close; }
65 bool strict_sync() { return true; }
66
67 // Declared in linked_streambuf.
68 T* component() { return storage_.get(); }
69protected:
70#if !NDNBOOST_WORKAROUND(__GNUC__, == 2)
71 NDNBOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base_type)
72#endif
73 direct_streambuf();
74
75 //--------------Virtual functions-----------------------------------------//
76
77 // Declared in linked_streambuf.
78 void close_impl(NDNBOOST_IOS::openmode m);
79 const std::type_info& component_type() const { return typeid(T); }
80 void* component_impl() { return component(); }
81#ifdef NDNBOOST_IOSTREAMS_NO_STREAM_TEMPLATES
82 public:
83#endif
84
85 // Declared in basic_streambuf.
86 int_type underflow();
87 int_type pbackfail(int_type c);
88 int_type overflow(int_type c);
89 pos_type seekoff( off_type off, NDNBOOST_IOS::seekdir way,
90 NDNBOOST_IOS::openmode which );
91 pos_type seekpos(pos_type sp, NDNBOOST_IOS::openmode which);
92private:
93 pos_type seek_impl( stream_offset off, NDNBOOST_IOS::seekdir way,
94 NDNBOOST_IOS::openmode which );
95 void init_input(any_tag) { }
96 void init_input(input);
97 void init_output(any_tag) { }
98 void init_output(output);
99 void init_get_area();
100 void init_put_area();
101 bool one_head() const;
102 bool two_head() const;
103 optional<T> storage_;
104 char_type *ibeg_, *iend_, *obeg_, *oend_;
105 bool auto_close_;
106};
107
108//------------------Implementation of direct_streambuf------------------------//
109
110template<typename T, typename Tr>
111direct_streambuf<T, Tr>::direct_streambuf()
112 : ibeg_(0), iend_(0), obeg_(0), oend_(0), auto_close_(true)
113{ this->set_true_eof(true); }
114
115template<typename T, typename Tr>
116void direct_streambuf<T, Tr>::open
117 (const T& t, std::streamsize, std::streamsize)
118{
119 storage_.reset(t);
120 init_input(category());
121 init_output(category());
122 setg(0, 0, 0);
123 setp(0, 0);
124 this->set_needs_close();
125}
126
127template<typename T, typename Tr>
128bool direct_streambuf<T, Tr>::is_open() const
129{ return ibeg_ != 0 || obeg_ != 0; }
130
131template<typename T, typename Tr>
132void direct_streambuf<T, Tr>::close()
133{
134 base_type* self = this;
135 detail::execute_all( detail::call_member_close(*self, NDNBOOST_IOS::in),
136 detail::call_member_close(*self, NDNBOOST_IOS::out),
137 detail::call_reset(storage_) );
138}
139
140template<typename T, typename Tr>
141typename direct_streambuf<T, Tr>::int_type
142direct_streambuf<T, Tr>::underflow()
143{
144 if (!ibeg_)
145 ndnboost::throw_exception(cant_read());
146 if (!gptr())
147 init_get_area();
148 return gptr() != iend_ ?
149 traits_type::to_int_type(*gptr()) :
150 traits_type::eof();
151}
152
153template<typename T, typename Tr>
154typename direct_streambuf<T, Tr>::int_type
155direct_streambuf<T, Tr>::pbackfail(int_type c)
156{
157 using namespace std;
158 if (!ibeg_)
159 ndnboost::throw_exception(cant_read());
160 if (gptr() != 0 && gptr() != ibeg_) {
161 gbump(-1);
162 if (!traits_type::eq_int_type(c, traits_type::eof()))
163 *gptr() = traits_type::to_char_type(c);
164 return traits_type::not_eof(c);
165 }
166 ndnboost::throw_exception(bad_putback());
167}
168
169template<typename T, typename Tr>
170typename direct_streambuf<T, Tr>::int_type
171direct_streambuf<T, Tr>::overflow(int_type c)
172{
173 using namespace std;
174 if (!obeg_)
175 ndnboost::throw_exception(NDNBOOST_IOSTREAMS_FAILURE("no write access"));
176 if (!pptr()) init_put_area();
177 if (!traits_type::eq_int_type(c, traits_type::eof())) {
178 if (pptr() == oend_)
179 ndnboost::throw_exception(
180 NDNBOOST_IOSTREAMS_FAILURE("write area exhausted")
181 );
182 *pptr() = traits_type::to_char_type(c);
183 pbump(1);
184 return c;
185 }
186 return traits_type::not_eof(c);
187}
188
189template<typename T, typename Tr>
190inline typename direct_streambuf<T, Tr>::pos_type
191direct_streambuf<T, Tr>::seekoff
192 (off_type off, NDNBOOST_IOS::seekdir way, NDNBOOST_IOS::openmode which)
193{ return seek_impl(off, way, which); }
194
195template<typename T, typename Tr>
196inline typename direct_streambuf<T, Tr>::pos_type
197direct_streambuf<T, Tr>::seekpos
198 (pos_type sp, NDNBOOST_IOS::openmode which)
199{
200 return seek_impl(position_to_offset(sp), NDNBOOST_IOS::beg, which);
201}
202
203template<typename T, typename Tr>
204void direct_streambuf<T, Tr>::close_impl(NDNBOOST_IOS::openmode which)
205{
206 if (which == NDNBOOST_IOS::in && ibeg_ != 0) {
207 setg(0, 0, 0);
208 ibeg_ = iend_ = 0;
209 }
210 if (which == NDNBOOST_IOS::out && obeg_ != 0) {
211 sync();
212 setp(0, 0);
213 obeg_ = oend_ = 0;
214 }
215 ndnboost::iostreams::close(*storage_, which);
216}
217
218template<typename T, typename Tr>
219typename direct_streambuf<T, Tr>::pos_type direct_streambuf<T, Tr>::seek_impl
220 (stream_offset off, NDNBOOST_IOS::seekdir way, NDNBOOST_IOS::openmode which)
221{
222 using namespace std;
223 NDNBOOST_IOS::openmode both = NDNBOOST_IOS::in | NDNBOOST_IOS::out;
224 if (two_head() && (which & both) == both)
225 ndnboost::throw_exception(bad_seek());
226 stream_offset result = -1;
227 bool one = one_head();
228 if (one && (pptr() != 0 || gptr()== 0))
229 init_get_area(); // Switch to input mode, for code reuse.
230 if (one || ((which & NDNBOOST_IOS::in) != 0 && ibeg_ != 0)) {
231 if (!gptr()) setg(ibeg_, ibeg_, iend_);
232 ptrdiff_t next = 0;
233 switch (way) {
234 case NDNBOOST_IOS::beg: next = off; break;
235 case NDNBOOST_IOS::cur: next = (gptr() - ibeg_) + off; break;
236 case NDNBOOST_IOS::end: next = (iend_ - ibeg_) + off; break;
237 default: NDNBOOST_ASSERT(0);
238 }
239 if (next < 0 || next > (iend_ - ibeg_))
240 ndnboost::throw_exception(bad_seek());
241 setg(ibeg_, ibeg_ + next, iend_);
242 result = next;
243 }
244 if (!one && (which & NDNBOOST_IOS::out) != 0 && obeg_ != 0) {
245 if (!pptr()) setp(obeg_, oend_);
246 ptrdiff_t next = 0;
247 switch (way) {
248 case NDNBOOST_IOS::beg: next = off; break;
249 case NDNBOOST_IOS::cur: next = (pptr() - obeg_) + off; break;
250 case NDNBOOST_IOS::end: next = (oend_ - obeg_) + off; break;
251 default: NDNBOOST_ASSERT(0);
252 }
253 if (next < 0 || next > (oend_ - obeg_))
254 ndnboost::throw_exception(bad_seek());
255 pbump(static_cast<int>(next - (pptr() - obeg_)));
256 result = next;
257 }
258 return offset_to_position(result);
259}
260
261template<typename T, typename Tr>
262void direct_streambuf<T, Tr>::init_input(input)
263{
264 std::pair<char_type*, char_type*> p = input_sequence(*storage_);
265 ibeg_ = p.first;
266 iend_ = p.second;
267}
268
269template<typename T, typename Tr>
270void direct_streambuf<T, Tr>::init_output(output)
271{
272 std::pair<char_type*, char_type*> p = output_sequence(*storage_);
273 obeg_ = p.first;
274 oend_ = p.second;
275}
276
277template<typename T, typename Tr>
278void direct_streambuf<T, Tr>::init_get_area()
279{
280 setg(ibeg_, ibeg_, iend_);
281 if (one_head() && pptr()) {
282 gbump(static_cast<int>(pptr() - obeg_));
283 setp(0, 0);
284 }
285}
286
287template<typename T, typename Tr>
288void direct_streambuf<T, Tr>::init_put_area()
289{
290 setp(obeg_, oend_);
291 if (one_head() && gptr()) {
292 pbump(static_cast<int>(gptr() - ibeg_));
293 setg(0, 0, 0);
294 }
295}
296
297template<typename T, typename Tr>
298inline bool direct_streambuf<T, Tr>::one_head() const
299{ return ibeg_ && obeg_ && ibeg_ == obeg_; }
300
301template<typename T, typename Tr>
302inline bool direct_streambuf<T, Tr>::two_head() const
303{ return ibeg_ && obeg_ && ibeg_ != obeg_; }
304
305//----------------------------------------------------------------------------//
306
307} // End namespace detail.
308
309} } // End namespaces iostreams, boost.
310
311#include <ndnboost/iostreams/detail/config/enable_warnings.hpp> // MSVC
312
313#endif // #ifndef NDNBOOST_IOSTREAMS_DETAIL_DIRECT_STREAMBUF_HPP_INCLUDED