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