Chris@16
|
1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
|
Chris@16
|
2 // (C) Copyright 2003-2007 Jonathan Turkanis
|
Chris@16
|
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
|
Chris@16
|
5
|
Chris@16
|
6 // See http://www.boost.org/libs/iostreams for documentation.
|
Chris@16
|
7
|
Chris@16
|
8 #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
|
Chris@16
|
9 #define BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
|
Chris@16
|
10
|
Chris@16
|
11 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
Chris@16
|
12 # pragma once
|
Chris@16
|
13 #endif
|
Chris@16
|
14
|
Chris@16
|
15 #include <boost/assert.hpp>
|
Chris@16
|
16 #include <exception>
|
Chris@16
|
17 #include <functional> // unary_function.
|
Chris@16
|
18 #include <iterator> // advance.
|
Chris@16
|
19 #include <list>
|
Chris@16
|
20 #include <memory> // allocator, auto_ptr.
|
Chris@16
|
21 #include <typeinfo>
|
Chris@16
|
22 #include <stdexcept> // logic_error, out_of_range.
|
Chris@16
|
23 #include <boost/checked_delete.hpp>
|
Chris@16
|
24 #include <boost/config.hpp> // BOOST_MSVC, template friends,
|
Chris@16
|
25 #include <boost/detail/workaround.hpp> // BOOST_NESTED_TEMPLATE
|
Chris@16
|
26 #include <boost/iostreams/constants.hpp>
|
Chris@16
|
27 #include <boost/iostreams/detail/access_control.hpp>
|
Chris@16
|
28 #include <boost/iostreams/detail/char_traits.hpp>
|
Chris@16
|
29 #include <boost/iostreams/detail/push.hpp>
|
Chris@16
|
30 #include <boost/iostreams/detail/streambuf.hpp> // pubsync.
|
Chris@16
|
31 #include <boost/iostreams/detail/wrap_unwrap.hpp>
|
Chris@16
|
32 #include <boost/iostreams/device/null.hpp>
|
Chris@16
|
33 #include <boost/iostreams/positioning.hpp>
|
Chris@16
|
34 #include <boost/iostreams/traits.hpp> // is_filter.
|
Chris@16
|
35 #include <boost/iostreams/stream_buffer.hpp>
|
Chris@16
|
36 #include <boost/next_prior.hpp>
|
Chris@16
|
37 #include <boost/shared_ptr.hpp>
|
Chris@16
|
38 #include <boost/static_assert.hpp>
|
Chris@16
|
39 #include <boost/throw_exception.hpp>
|
Chris@16
|
40 #include <boost/type_traits/is_convertible.hpp>
|
Chris@16
|
41 #include <boost/type.hpp>
|
Chris@16
|
42 #include <boost/iostreams/detail/execute.hpp> // VC6.5 requires this
|
Chris@16
|
43 #if BOOST_WORKAROUND(BOOST_MSVC, < 1310) // #include order
|
Chris@16
|
44 # include <boost/mpl/int.hpp>
|
Chris@16
|
45 #endif
|
Chris@16
|
46
|
Chris@16
|
47 // Sometimes type_info objects must be compared by name. Borrowed from
|
Chris@16
|
48 // Boost.Python and Boost.Function.
|
Chris@16
|
49 #if (defined(__GNUC__) && __GNUC__ >= 3) || \
|
Chris@16
|
50 defined(_AIX) || \
|
Chris@16
|
51 (defined(__sgi) && defined(__host_mips)) || \
|
Chris@16
|
52 (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) \
|
Chris@16
|
53 /**/
|
Chris@16
|
54 # include <cstring>
|
Chris@16
|
55 # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) \
|
Chris@16
|
56 (std::strcmp((X).name(),(Y).name()) == 0)
|
Chris@16
|
57 #else
|
Chris@16
|
58 # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
|
Chris@16
|
59 #endif
|
Chris@16
|
60
|
Chris@16
|
61 // Deprecated
|
Chris@16
|
62 #define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \
|
Chris@16
|
63 chain.component_type( index ) \
|
Chris@16
|
64 /**/
|
Chris@16
|
65
|
Chris@16
|
66 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
|
Chris@16
|
67 # define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \
|
Chris@16
|
68 chain.component< target >( index ) \
|
Chris@16
|
69 /**/
|
Chris@16
|
70 #else
|
Chris@16
|
71 # define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \
|
Chris@16
|
72 chain.component( index, ::boost::type< target >() ) \
|
Chris@16
|
73 /**/
|
Chris@16
|
74 #endif
|
Chris@16
|
75
|
Chris@16
|
76 namespace boost { namespace iostreams {
|
Chris@16
|
77
|
Chris@16
|
78 //--------------Definition of chain and wchain--------------------------------//
|
Chris@16
|
79
|
Chris@16
|
80 namespace detail {
|
Chris@16
|
81
|
Chris@16
|
82 template<typename Chain> class chain_client;
|
Chris@16
|
83
|
Chris@16
|
84 //
|
Chris@16
|
85 // Concept name: Chain.
|
Chris@16
|
86 // Description: Represents a chain of stream buffers which provides access
|
Chris@16
|
87 // to the first buffer in the chain and sends notifications when the
|
Chris@16
|
88 // streambufs are added to or removed from chain.
|
Chris@16
|
89 // Refines: Closable device with mode equal to typename Chain::mode.
|
Chris@16
|
90 // Models: chain, converting_chain.
|
Chris@16
|
91 // Example:
|
Chris@16
|
92 //
|
Chris@16
|
93 // class chain {
|
Chris@16
|
94 // public:
|
Chris@16
|
95 // typedef xxx chain_type;
|
Chris@16
|
96 // typedef xxx client_type;
|
Chris@16
|
97 // typedef xxx mode;
|
Chris@16
|
98 // bool is_complete() const; // Ready for i/o.
|
Chris@16
|
99 // template<typename T>
|
Chris@16
|
100 // void push( const T& t, // Adds a stream buffer to
|
Chris@16
|
101 // streamsize, // chain, based on t, with
|
Chris@16
|
102 // streamsize ); // given buffer and putback
|
Chris@16
|
103 // // buffer sizes. Pass -1 to
|
Chris@16
|
104 // // request default size.
|
Chris@16
|
105 // protected:
|
Chris@16
|
106 // void register_client(client_type* client); // Associate client.
|
Chris@16
|
107 // void notify(); // Notify client.
|
Chris@16
|
108 // };
|
Chris@16
|
109 //
|
Chris@16
|
110
|
Chris@16
|
111 //
|
Chris@16
|
112 // Description: Represents a chain of filters with an optional device at the
|
Chris@16
|
113 // end.
|
Chris@16
|
114 // Template parameters:
|
Chris@16
|
115 // Self - A class deriving from the current instantiation of this template.
|
Chris@16
|
116 // This is an example of the Curiously Recurring Template Pattern.
|
Chris@16
|
117 // Ch - The character type.
|
Chris@16
|
118 // Tr - The character traits type.
|
Chris@16
|
119 // Alloc - The allocator type.
|
Chris@16
|
120 // Mode - A mode tag.
|
Chris@16
|
121 //
|
Chris@16
|
122 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
|
Chris@16
|
123 class chain_base {
|
Chris@16
|
124 public:
|
Chris@16
|
125 typedef Ch char_type;
|
Chris@16
|
126 BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
|
Chris@16
|
127 typedef Alloc allocator_type;
|
Chris@16
|
128 typedef Mode mode;
|
Chris@16
|
129 struct category
|
Chris@16
|
130 : Mode,
|
Chris@16
|
131 device_tag
|
Chris@16
|
132 { };
|
Chris@16
|
133 typedef chain_client<Self> client_type;
|
Chris@16
|
134 friend class chain_client<Self>;
|
Chris@16
|
135 private:
|
Chris@16
|
136 typedef linked_streambuf<Ch> streambuf_type;
|
Chris@16
|
137 typedef std::list<streambuf_type*> list_type;
|
Chris@16
|
138 typedef chain_base<Self, Ch, Tr, Alloc, Mode> my_type;
|
Chris@16
|
139 protected:
|
Chris@16
|
140 chain_base() : pimpl_(new chain_impl) { }
|
Chris@16
|
141 chain_base(const chain_base& rhs): pimpl_(rhs.pimpl_) { }
|
Chris@16
|
142 public:
|
Chris@16
|
143
|
Chris@16
|
144 // dual_use is a pseudo-mode to facilitate filter writing,
|
Chris@16
|
145 // not a genuine mode.
|
Chris@16
|
146 BOOST_STATIC_ASSERT((!is_convertible<mode, dual_use>::value));
|
Chris@16
|
147
|
Chris@16
|
148 //----------Buffer sizing-------------------------------------------------//
|
Chris@16
|
149
|
Chris@16
|
150 // Sets the size of the buffer created for the devices to be added to this
|
Chris@16
|
151 // chain. Does not affect the size of the buffer for devices already
|
Chris@16
|
152 // added.
|
Chris@16
|
153 void set_device_buffer_size(std::streamsize n)
|
Chris@16
|
154 { pimpl_->device_buffer_size_ = n; }
|
Chris@16
|
155
|
Chris@16
|
156 // Sets the size of the buffer created for the filters to be added
|
Chris@16
|
157 // to this chain. Does not affect the size of the buffer for filters already
|
Chris@16
|
158 // added.
|
Chris@16
|
159 void set_filter_buffer_size(std::streamsize n)
|
Chris@16
|
160 { pimpl_->filter_buffer_size_ = n; }
|
Chris@16
|
161
|
Chris@16
|
162 // Sets the size of the putback buffer for filters and devices to be added
|
Chris@16
|
163 // to this chain. Does not affect the size of the buffer for filters or
|
Chris@16
|
164 // devices already added.
|
Chris@16
|
165 void set_pback_size(std::streamsize n)
|
Chris@16
|
166 { pimpl_->pback_size_ = n; }
|
Chris@16
|
167
|
Chris@16
|
168 //----------Device interface----------------------------------------------//
|
Chris@16
|
169
|
Chris@16
|
170 std::streamsize read(char_type* s, std::streamsize n);
|
Chris@16
|
171 std::streamsize write(const char_type* s, std::streamsize n);
|
Chris@16
|
172 std::streampos seek(stream_offset off, BOOST_IOS::seekdir way);
|
Chris@16
|
173
|
Chris@16
|
174 //----------Direct component access---------------------------------------//
|
Chris@16
|
175
|
Chris@16
|
176 const std::type_info& component_type(int n) const
|
Chris@16
|
177 {
|
Chris@16
|
178 if (static_cast<size_type>(n) >= size())
|
Chris@16
|
179 boost::throw_exception(std::out_of_range("bad chain offset"));
|
Chris@16
|
180 return (*boost::next(list().begin(), n))->component_type();
|
Chris@16
|
181 }
|
Chris@16
|
182
|
Chris@16
|
183 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
|
Chris@16
|
184 // Deprecated.
|
Chris@16
|
185 template<int N>
|
Chris@16
|
186 const std::type_info& component_type() const { return component_type(N); }
|
Chris@16
|
187
|
Chris@16
|
188 template<typename T>
|
Chris@16
|
189 T* component(int n) const { return component(n, boost::type<T>()); }
|
Chris@16
|
190
|
Chris@16
|
191 // Deprecated.
|
Chris@16
|
192 template<int N, typename T>
|
Chris@16
|
193 T* component() const { return component<T>(N); }
|
Chris@16
|
194 #endif
|
Chris@16
|
195
|
Chris@16
|
196 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
|
Chris@16
|
197 private:
|
Chris@16
|
198 #endif
|
Chris@16
|
199 template<typename T>
|
Chris@16
|
200 T* component(int n, boost::type<T>) const
|
Chris@16
|
201 {
|
Chris@16
|
202 if (static_cast<size_type>(n) >= size())
|
Chris@16
|
203 boost::throw_exception(std::out_of_range("bad chain offset"));
|
Chris@16
|
204 streambuf_type* link = *boost::next(list().begin(), n);
|
Chris@16
|
205 if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), typeid(T)))
|
Chris@16
|
206 return static_cast<T*>(link->component_impl());
|
Chris@16
|
207 else
|
Chris@16
|
208 return 0;
|
Chris@16
|
209 }
|
Chris@16
|
210 public:
|
Chris@16
|
211
|
Chris@16
|
212 //----------Container-like interface--------------------------------------//
|
Chris@16
|
213
|
Chris@16
|
214 typedef typename list_type::size_type size_type;
|
Chris@16
|
215 streambuf_type& front() { return *list().front(); }
|
Chris@16
|
216 BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
|
Chris@16
|
217 void pop();
|
Chris@16
|
218 bool empty() const { return list().empty(); }
|
Chris@16
|
219 size_type size() const { return list().size(); }
|
Chris@16
|
220 void reset();
|
Chris@16
|
221
|
Chris@16
|
222 //----------Additional i/o functions--------------------------------------//
|
Chris@16
|
223
|
Chris@16
|
224 // Returns true if this chain is non-empty and its final link
|
Chris@16
|
225 // is a source or sink, i.e., if it is ready to perform i/o.
|
Chris@16
|
226 bool is_complete() const;
|
Chris@16
|
227 bool auto_close() const;
|
Chris@16
|
228 void set_auto_close(bool close);
|
Chris@16
|
229 bool sync() { return front().BOOST_IOSTREAMS_PUBSYNC() != -1; }
|
Chris@16
|
230 bool strict_sync();
|
Chris@16
|
231 private:
|
Chris@16
|
232 template<typename T>
|
Chris@16
|
233 void push_impl(const T& t, std::streamsize buffer_size = -1,
|
Chris@16
|
234 std::streamsize pback_size = -1)
|
Chris@16
|
235 {
|
Chris@16
|
236 typedef typename iostreams::category_of<T>::type category;
|
Chris@16
|
237 typedef typename unwrap_ios<T>::type component_type;
|
Chris@16
|
238 typedef stream_buffer<
|
Chris@16
|
239 component_type,
|
Chris@16
|
240 BOOST_IOSTREAMS_CHAR_TRAITS(char_type),
|
Chris@16
|
241 Alloc, Mode
|
Chris@16
|
242 > streambuf_t;
|
Chris@16
|
243 typedef typename list_type::iterator iterator;
|
Chris@16
|
244 BOOST_STATIC_ASSERT((is_convertible<category, Mode>::value));
|
Chris@16
|
245 if (is_complete())
|
Chris@16
|
246 boost::throw_exception(std::logic_error("chain complete"));
|
Chris@16
|
247 streambuf_type* prev = !empty() ? list().back() : 0;
|
Chris@16
|
248 buffer_size =
|
Chris@16
|
249 buffer_size != -1 ?
|
Chris@16
|
250 buffer_size :
|
Chris@16
|
251 iostreams::optimal_buffer_size(t);
|
Chris@16
|
252 pback_size =
|
Chris@16
|
253 pback_size != -1 ?
|
Chris@16
|
254 pback_size :
|
Chris@16
|
255 pimpl_->pback_size_;
|
Chris@16
|
256 std::auto_ptr<streambuf_t>
|
Chris@16
|
257 buf(new streambuf_t(t, buffer_size, pback_size));
|
Chris@16
|
258 list().push_back(buf.get());
|
Chris@16
|
259 buf.release();
|
Chris@16
|
260 if (is_device<component_type>::value) {
|
Chris@16
|
261 pimpl_->flags_ |= f_complete | f_open;
|
Chris@16
|
262 for ( iterator first = list().begin(),
|
Chris@16
|
263 last = list().end();
|
Chris@16
|
264 first != last;
|
Chris@16
|
265 ++first )
|
Chris@16
|
266 {
|
Chris@16
|
267 (*first)->set_needs_close();
|
Chris@16
|
268 }
|
Chris@16
|
269 }
|
Chris@16
|
270 if (prev) prev->set_next(list().back());
|
Chris@16
|
271 notify();
|
Chris@16
|
272 }
|
Chris@16
|
273
|
Chris@16
|
274 list_type& list() { return pimpl_->links_; }
|
Chris@16
|
275 const list_type& list() const { return pimpl_->links_; }
|
Chris@16
|
276 void register_client(client_type* client) { pimpl_->client_ = client; }
|
Chris@16
|
277 void notify() { if (pimpl_->client_) pimpl_->client_->notify(); }
|
Chris@16
|
278
|
Chris@16
|
279 //----------Nested classes------------------------------------------------//
|
Chris@16
|
280
|
Chris@16
|
281 static void close(streambuf_type* b, BOOST_IOS::openmode m)
|
Chris@16
|
282 {
|
Chris@16
|
283 if (m == BOOST_IOS::out && is_convertible<Mode, output>::value)
|
Chris@16
|
284 b->BOOST_IOSTREAMS_PUBSYNC();
|
Chris@16
|
285 b->close(m);
|
Chris@16
|
286 }
|
Chris@16
|
287
|
Chris@16
|
288 static void set_next(streambuf_type* b, streambuf_type* next)
|
Chris@16
|
289 { b->set_next(next); }
|
Chris@16
|
290
|
Chris@16
|
291 static void set_auto_close(streambuf_type* b, bool close)
|
Chris@16
|
292 { b->set_auto_close(close); }
|
Chris@16
|
293
|
Chris@16
|
294 struct closer : public std::unary_function<streambuf_type*, void> {
|
Chris@16
|
295 closer(BOOST_IOS::openmode m) : mode_(m) { }
|
Chris@16
|
296 void operator() (streambuf_type* b)
|
Chris@16
|
297 {
|
Chris@16
|
298 close(b, mode_);
|
Chris@16
|
299 }
|
Chris@16
|
300 BOOST_IOS::openmode mode_;
|
Chris@16
|
301 };
|
Chris@16
|
302 friend struct closer;
|
Chris@16
|
303
|
Chris@16
|
304 enum flags {
|
Chris@16
|
305 f_complete = 1,
|
Chris@16
|
306 f_open = 2,
|
Chris@16
|
307 f_auto_close = 4
|
Chris@16
|
308 };
|
Chris@16
|
309
|
Chris@16
|
310 struct chain_impl {
|
Chris@16
|
311 chain_impl()
|
Chris@16
|
312 : client_(0), device_buffer_size_(default_device_buffer_size),
|
Chris@16
|
313 filter_buffer_size_(default_filter_buffer_size),
|
Chris@16
|
314 pback_size_(default_pback_buffer_size),
|
Chris@16
|
315 flags_(f_auto_close)
|
Chris@16
|
316 { }
|
Chris@16
|
317 ~chain_impl()
|
Chris@16
|
318 {
|
Chris@16
|
319 try { close(); } catch (...) { }
|
Chris@16
|
320 try { reset(); } catch (...) { }
|
Chris@16
|
321 }
|
Chris@16
|
322 void close()
|
Chris@16
|
323 {
|
Chris@16
|
324 if ((flags_ & f_open) != 0) {
|
Chris@16
|
325 flags_ &= ~f_open;
|
Chris@16
|
326 stream_buffer< basic_null_device<Ch, Mode> > null;
|
Chris@16
|
327 if ((flags_ & f_complete) == 0) {
|
Chris@16
|
328 null.open(basic_null_device<Ch, Mode>());
|
Chris@16
|
329 set_next(links_.back(), &null);
|
Chris@16
|
330 }
|
Chris@16
|
331 links_.front()->BOOST_IOSTREAMS_PUBSYNC();
|
Chris@16
|
332 try {
|
Chris@16
|
333 boost::iostreams::detail::execute_foreach(
|
Chris@16
|
334 links_.rbegin(), links_.rend(),
|
Chris@16
|
335 closer(BOOST_IOS::in)
|
Chris@16
|
336 );
|
Chris@16
|
337 } catch (...) {
|
Chris@16
|
338 try {
|
Chris@16
|
339 boost::iostreams::detail::execute_foreach(
|
Chris@16
|
340 links_.begin(), links_.end(),
|
Chris@16
|
341 closer(BOOST_IOS::out)
|
Chris@16
|
342 );
|
Chris@16
|
343 } catch (...) { }
|
Chris@16
|
344 throw;
|
Chris@16
|
345 }
|
Chris@16
|
346 boost::iostreams::detail::execute_foreach(
|
Chris@16
|
347 links_.begin(), links_.end(),
|
Chris@16
|
348 closer(BOOST_IOS::out)
|
Chris@16
|
349 );
|
Chris@16
|
350 }
|
Chris@16
|
351 }
|
Chris@16
|
352 void reset()
|
Chris@16
|
353 {
|
Chris@16
|
354 typedef typename list_type::iterator iterator;
|
Chris@16
|
355 for ( iterator first = links_.begin(),
|
Chris@16
|
356 last = links_.end();
|
Chris@16
|
357 first != last;
|
Chris@16
|
358 ++first )
|
Chris@16
|
359 {
|
Chris@16
|
360 if ( (flags_ & f_complete) == 0 ||
|
Chris@16
|
361 (flags_ & f_auto_close) == 0 )
|
Chris@16
|
362 {
|
Chris@16
|
363 set_auto_close(*first, false);
|
Chris@16
|
364 }
|
Chris@16
|
365 streambuf_type* buf = 0;
|
Chris@16
|
366 std::swap(buf, *first);
|
Chris@16
|
367 delete buf;
|
Chris@16
|
368 }
|
Chris@16
|
369 links_.clear();
|
Chris@16
|
370 flags_ &= ~f_complete;
|
Chris@16
|
371 flags_ &= ~f_open;
|
Chris@16
|
372 }
|
Chris@16
|
373 list_type links_;
|
Chris@16
|
374 client_type* client_;
|
Chris@16
|
375 std::streamsize device_buffer_size_,
|
Chris@16
|
376 filter_buffer_size_,
|
Chris@16
|
377 pback_size_;
|
Chris@16
|
378 int flags_;
|
Chris@16
|
379 };
|
Chris@16
|
380 friend struct chain_impl;
|
Chris@16
|
381
|
Chris@16
|
382 //----------Member data---------------------------------------------------//
|
Chris@16
|
383
|
Chris@16
|
384 private:
|
Chris@16
|
385 shared_ptr<chain_impl> pimpl_;
|
Chris@16
|
386 };
|
Chris@16
|
387
|
Chris@16
|
388 } // End namespace detail.
|
Chris@16
|
389
|
Chris@16
|
390 //
|
Chris@16
|
391 // Macro: BOOST_IOSTREAMS_DECL_CHAIN(name, category)
|
Chris@16
|
392 // Description: Defines a template derived from chain_base appropriate for a
|
Chris@16
|
393 // particular i/o category. The template has the following parameters:
|
Chris@16
|
394 // Ch - The character type.
|
Chris@16
|
395 // Tr - The character traits type.
|
Chris@16
|
396 // Alloc - The allocator type.
|
Chris@16
|
397 // Macro parameters:
|
Chris@16
|
398 // name_ - The name of the template to be defined.
|
Chris@16
|
399 // category_ - The i/o category of the template to be defined.
|
Chris@16
|
400 //
|
Chris@16
|
401 #define BOOST_IOSTREAMS_DECL_CHAIN(name_, default_char_) \
|
Chris@16
|
402 template< typename Mode, typename Ch = default_char_, \
|
Chris@16
|
403 typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch), \
|
Chris@16
|
404 typename Alloc = std::allocator<Ch> > \
|
Chris@16
|
405 class name_ : public boost::iostreams::detail::chain_base< \
|
Chris@16
|
406 name_<Mode, Ch, Tr, Alloc>, \
|
Chris@16
|
407 Ch, Tr, Alloc, Mode \
|
Chris@16
|
408 > \
|
Chris@16
|
409 { \
|
Chris@16
|
410 public: \
|
Chris@16
|
411 struct category : device_tag, Mode { }; \
|
Chris@16
|
412 typedef Mode mode; \
|
Chris@16
|
413 private: \
|
Chris@16
|
414 typedef boost::iostreams::detail::chain_base< \
|
Chris@16
|
415 name_<Mode, Ch, Tr, Alloc>, \
|
Chris@16
|
416 Ch, Tr, Alloc, Mode \
|
Chris@16
|
417 > base_type; \
|
Chris@16
|
418 public: \
|
Chris@16
|
419 typedef Ch char_type; \
|
Chris@16
|
420 typedef Tr traits_type; \
|
Chris@16
|
421 typedef typename traits_type::int_type int_type; \
|
Chris@16
|
422 typedef typename traits_type::off_type off_type; \
|
Chris@16
|
423 name_() { } \
|
Chris@16
|
424 name_(const name_& rhs) : base_type(rhs) { } \
|
Chris@16
|
425 name_& operator=(const name_& rhs) \
|
Chris@16
|
426 { base_type::operator=(rhs); return *this; } \
|
Chris@16
|
427 }; \
|
Chris@16
|
428 /**/
|
Chris@16
|
429 BOOST_IOSTREAMS_DECL_CHAIN(chain, char)
|
Chris@16
|
430 BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t)
|
Chris@16
|
431 #undef BOOST_IOSTREAMS_DECL_CHAIN
|
Chris@16
|
432
|
Chris@16
|
433 //--------------Definition of chain_client------------------------------------//
|
Chris@16
|
434
|
Chris@16
|
435 namespace detail {
|
Chris@16
|
436
|
Chris@16
|
437 //
|
Chris@16
|
438 // Template name: chain_client
|
Chris@16
|
439 // Description: Class whose instances provide access to an underlying chain
|
Chris@16
|
440 // using an interface similar to the chains.
|
Chris@16
|
441 // Subclasses: the various stream and stream buffer templates.
|
Chris@16
|
442 //
|
Chris@16
|
443 template<typename Chain>
|
Chris@16
|
444 class chain_client {
|
Chris@16
|
445 public:
|
Chris@16
|
446 typedef Chain chain_type;
|
Chris@16
|
447 typedef typename chain_type::char_type char_type;
|
Chris@16
|
448 typedef typename chain_type::traits_type traits_type;
|
Chris@16
|
449 typedef typename chain_type::size_type size_type;
|
Chris@16
|
450 typedef typename chain_type::mode mode;
|
Chris@16
|
451
|
Chris@16
|
452 chain_client(chain_type* chn = 0) : chain_(chn ) { }
|
Chris@16
|
453 chain_client(chain_client* client) : chain_(client->chain_) { }
|
Chris@16
|
454 virtual ~chain_client() { }
|
Chris@16
|
455
|
Chris@16
|
456 const std::type_info& component_type(int n) const
|
Chris@16
|
457 { return chain_->component_type(n); }
|
Chris@16
|
458
|
Chris@16
|
459 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
|
Chris@16
|
460 // Deprecated.
|
Chris@16
|
461 template<int N>
|
Chris@16
|
462 const std::type_info& component_type() const
|
Chris@16
|
463 { return chain_->BOOST_NESTED_TEMPLATE component_type<N>(); }
|
Chris@16
|
464
|
Chris@16
|
465 template<typename T>
|
Chris@16
|
466 T* component(int n) const
|
Chris@16
|
467 { return chain_->BOOST_NESTED_TEMPLATE component<T>(n); }
|
Chris@16
|
468
|
Chris@16
|
469 // Deprecated.
|
Chris@16
|
470 template<int N, typename T>
|
Chris@16
|
471 T* component() const
|
Chris@16
|
472 { return chain_->BOOST_NESTED_TEMPLATE component<N, T>(); }
|
Chris@16
|
473 #else
|
Chris@16
|
474 template<typename T>
|
Chris@16
|
475 T* component(int n, boost::type<T> t) const
|
Chris@16
|
476 { return chain_->component(n, t); }
|
Chris@16
|
477 #endif
|
Chris@16
|
478
|
Chris@16
|
479 bool is_complete() const { return chain_->is_complete(); }
|
Chris@16
|
480 bool auto_close() const { return chain_->auto_close(); }
|
Chris@16
|
481 void set_auto_close(bool close) { chain_->set_auto_close(close); }
|
Chris@16
|
482 bool strict_sync() { return chain_->strict_sync(); }
|
Chris@16
|
483 void set_device_buffer_size(std::streamsize n)
|
Chris@16
|
484 { chain_->set_device_buffer_size(n); }
|
Chris@16
|
485 void set_filter_buffer_size(std::streamsize n)
|
Chris@16
|
486 { chain_->set_filter_buffer_size(n); }
|
Chris@16
|
487 void set_pback_size(std::streamsize n) { chain_->set_pback_size(n); }
|
Chris@16
|
488 BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
|
Chris@16
|
489 void pop() { chain_->pop(); }
|
Chris@16
|
490 bool empty() const { return chain_->empty(); }
|
Chris@16
|
491 size_type size() { return chain_->size(); }
|
Chris@16
|
492 void reset() { chain_->reset(); }
|
Chris@16
|
493
|
Chris@16
|
494 // Returns a copy of the underlying chain.
|
Chris@16
|
495 chain_type filters() { return *chain_; }
|
Chris@16
|
496 chain_type filters() const { return *chain_; }
|
Chris@16
|
497 protected:
|
Chris@16
|
498 template<typename T>
|
Chris@16
|
499 void push_impl(const T& t BOOST_IOSTREAMS_PUSH_PARAMS())
|
Chris@16
|
500 { chain_->push(t BOOST_IOSTREAMS_PUSH_ARGS()); }
|
Chris@16
|
501 chain_type& ref() { return *chain_; }
|
Chris@16
|
502 void set_chain(chain_type* c)
|
Chris@16
|
503 { chain_ = c; chain_->register_client(this); }
|
Chris@16
|
504 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) && \
|
Chris@16
|
505 (!BOOST_WORKAROUND(__BORLANDC__, < 0x600))
|
Chris@16
|
506 template<typename S, typename C, typename T, typename A, typename M>
|
Chris@16
|
507 friend class chain_base;
|
Chris@16
|
508 #else
|
Chris@16
|
509 public:
|
Chris@16
|
510 #endif
|
Chris@16
|
511 virtual void notify() { }
|
Chris@16
|
512 private:
|
Chris@16
|
513 chain_type* chain_;
|
Chris@16
|
514 };
|
Chris@16
|
515
|
Chris@16
|
516 //--------------Implementation of chain_base----------------------------------//
|
Chris@16
|
517
|
Chris@16
|
518 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
|
Chris@16
|
519 inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::read
|
Chris@16
|
520 (char_type* s, std::streamsize n)
|
Chris@16
|
521 { return iostreams::read(*list().front(), s, n); }
|
Chris@16
|
522
|
Chris@16
|
523 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
|
Chris@16
|
524 inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::write
|
Chris@16
|
525 (const char_type* s, std::streamsize n)
|
Chris@16
|
526 { return iostreams::write(*list().front(), s, n); }
|
Chris@16
|
527
|
Chris@16
|
528 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
|
Chris@16
|
529 inline std::streampos chain_base<Self, Ch, Tr, Alloc, Mode>::seek
|
Chris@16
|
530 (stream_offset off, BOOST_IOS::seekdir way)
|
Chris@16
|
531 { return iostreams::seek(*list().front(), off, way); }
|
Chris@16
|
532
|
Chris@16
|
533 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
|
Chris@16
|
534 void chain_base<Self, Ch, Tr, Alloc, Mode>::reset()
|
Chris@16
|
535 {
|
Chris@16
|
536 using namespace std;
|
Chris@16
|
537 pimpl_->close();
|
Chris@16
|
538 pimpl_->reset();
|
Chris@16
|
539 }
|
Chris@16
|
540
|
Chris@16
|
541 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
|
Chris@16
|
542 bool chain_base<Self, Ch, Tr, Alloc, Mode>::is_complete() const
|
Chris@16
|
543 {
|
Chris@16
|
544 return (pimpl_->flags_ & f_complete) != 0;
|
Chris@16
|
545 }
|
Chris@16
|
546
|
Chris@16
|
547 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
|
Chris@16
|
548 bool chain_base<Self, Ch, Tr, Alloc, Mode>::auto_close() const
|
Chris@16
|
549 {
|
Chris@16
|
550 return (pimpl_->flags_ & f_auto_close) != 0;
|
Chris@16
|
551 }
|
Chris@16
|
552
|
Chris@16
|
553 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
|
Chris@16
|
554 void chain_base<Self, Ch, Tr, Alloc, Mode>::set_auto_close(bool close)
|
Chris@16
|
555 {
|
Chris@16
|
556 pimpl_->flags_ =
|
Chris@16
|
557 (pimpl_->flags_ & ~f_auto_close) |
|
Chris@16
|
558 (close ? f_auto_close : 0);
|
Chris@16
|
559 }
|
Chris@16
|
560
|
Chris@16
|
561 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
|
Chris@16
|
562 bool chain_base<Self, Ch, Tr, Alloc, Mode>::strict_sync()
|
Chris@16
|
563 {
|
Chris@16
|
564 typedef typename list_type::iterator iterator;
|
Chris@16
|
565 bool result = true;
|
Chris@16
|
566 for ( iterator first = list().begin(),
|
Chris@16
|
567 last = list().end();
|
Chris@16
|
568 first != last;
|
Chris@16
|
569 ++first )
|
Chris@16
|
570 {
|
Chris@16
|
571 bool s = (*first)->strict_sync();
|
Chris@16
|
572 result = result && s;
|
Chris@16
|
573 }
|
Chris@16
|
574 return result;
|
Chris@16
|
575 }
|
Chris@16
|
576
|
Chris@16
|
577 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
|
Chris@16
|
578 void chain_base<Self, Ch, Tr, Alloc, Mode>::pop()
|
Chris@16
|
579 {
|
Chris@16
|
580 BOOST_ASSERT(!empty());
|
Chris@16
|
581 if (auto_close())
|
Chris@16
|
582 pimpl_->close();
|
Chris@16
|
583 streambuf_type* buf = 0;
|
Chris@16
|
584 std::swap(buf, list().back());
|
Chris@16
|
585 buf->set_auto_close(false);
|
Chris@16
|
586 buf->set_next(0);
|
Chris@16
|
587 delete buf;
|
Chris@16
|
588 list().pop_back();
|
Chris@16
|
589 pimpl_->flags_ &= ~f_complete;
|
Chris@16
|
590 if (auto_close() || list().empty())
|
Chris@16
|
591 pimpl_->flags_ &= ~f_open;
|
Chris@16
|
592 }
|
Chris@16
|
593
|
Chris@16
|
594 } // End namespace detail.
|
Chris@16
|
595
|
Chris@16
|
596 } } // End namespaces iostreams, boost.
|
Chris@16
|
597
|
Chris@16
|
598 #endif // #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
|