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