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