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 |
---|