Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / archive / iterators / wchar_from_mb.hpp
1 #ifndef BOOST_ARCHIVE_ITERATORS_WCHAR_FROM_MB_HPP
2 #define BOOST_ARCHIVE_ITERATORS_WCHAR_FROM_MB_HPP
3
4 // MS compatible compilers support #pragma once
5 #if defined(_MSC_VER)
6 # pragma once
7 #endif
8
9 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
10 // wchar_from_mb.hpp
11
12 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
13 // Use, modification and distribution is subject to the Boost Software
14 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
15 // http://www.boost.org/LICENSE_1_0.txt)
16
17 //  See http://www.boost.org for updates, documentation, and revision history.
18
19 #include <cctype>
20 #include <cstddef> // size_t
21 #ifndef BOOST_NO_CWCHAR
22 #include <cwchar>  // mbstate_t
23 #endif
24 #include <algorithm> // copy
25
26 #include <boost/config.hpp>
27 #if defined(BOOST_NO_STDC_NAMESPACE)
28 namespace std{ 
29     using ::mbstate_t;
30 } // namespace std
31 #endif
32 #include <boost/assert.hpp>
33 #include <boost/core/ignore_unused.hpp>
34 #include <boost/array.hpp>
35 #include <boost/iterator/iterator_adaptor.hpp>
36 #include <boost/archive/detail/utf8_codecvt_facet.hpp>
37 #include <boost/archive/iterators/dataflow_exception.hpp>
38 #include <boost/serialization/throw_exception.hpp>
39
40 #include <iostream>
41
42 namespace boost { 
43 namespace archive {
44 namespace iterators {
45
46 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
47 // class used by text archives to translate char strings to wchar_t
48 // strings of the currently selected locale
49 template<class Base>
50 class wchar_from_mb 
51     : public boost::iterator_adaptor<
52         wchar_from_mb<Base>, 
53         Base, 
54         wchar_t,
55         single_pass_traversal_tag,
56         wchar_t
57     >
58 {
59     friend class boost::iterator_core_access;
60     typedef typename boost::iterator_adaptor<
61         wchar_from_mb<Base>, 
62         Base, 
63         wchar_t,
64         single_pass_traversal_tag,
65         wchar_t
66     > super_t;
67
68     typedef wchar_from_mb<Base> this_t;
69
70     void drain();
71
72     wchar_t dereference() const {
73         if(m_output.m_next == m_output.m_next_available)
74             return static_cast<wchar_t>(0);
75         return * m_output.m_next;
76     }
77
78     void increment(){
79         if(m_output.m_next == m_output.m_next_available)
80             return;
81         if(++m_output.m_next == m_output.m_next_available){
82             if(m_input.m_done)
83                 return;
84             drain();
85         }
86     }
87
88     bool equal(this_t const & rhs) const {
89         return dereference() == rhs.dereference();
90     }
91
92     boost::archive::detail::utf8_codecvt_facet m_codecvt_facet;
93     std::mbstate_t m_mbs;
94
95     template<typename T>
96     struct sliding_buffer {
97         boost::array<T, 32> m_buffer;
98         typename boost::array<T, 32>::const_iterator m_next_available;
99         typename boost::array<T, 32>::iterator m_next;
100         bool m_done;
101         // default ctor
102         sliding_buffer() :
103             m_next_available(m_buffer.begin()),
104             m_next(m_buffer.begin()),
105             m_done(false)
106         {}
107         // copy ctor
108         sliding_buffer(const sliding_buffer & rhs) :
109             m_next_available(
110                 std::copy(
111                     rhs.m_buffer.begin(),
112                     rhs.m_next_available,
113                     m_buffer.begin()
114                 )
115             ),
116             m_next(
117                 m_buffer.begin() + (rhs.m_next - rhs.m_buffer.begin())
118             ),
119             m_done(rhs.m_done)
120         {}
121     };
122
123     sliding_buffer<typename iterator_value<Base>::type> m_input;
124     sliding_buffer<typename iterator_value<this_t>::type> m_output;
125
126 public:
127     // make composible buy using templated constructor
128     template<class T>
129     wchar_from_mb(T start) : 
130         super_t(Base(static_cast< T >(start))),
131         m_mbs(std::mbstate_t())
132     {
133         BOOST_ASSERT(std::mbsinit(&m_mbs));
134         drain();
135     }
136     // default constructor used as an end iterator
137     wchar_from_mb(){}
138
139     // copy ctor
140     wchar_from_mb(const wchar_from_mb & rhs) :
141         super_t(rhs.base_reference()),
142         m_mbs(rhs.m_mbs),
143         m_input(rhs.m_input),
144         m_output(rhs.m_output)
145     {}
146 };
147
148 template<class Base>
149 void wchar_from_mb<Base>::drain(){
150     BOOST_ASSERT(! m_input.m_done);
151     for(;;){
152         typename boost::iterators::iterator_reference<Base>::type c = *(this->base_reference());
153         // a null character in a multibyte stream is takes as end of string
154         if(0 == c){
155             m_input.m_done = true;
156             break;
157         }
158         ++(this->base_reference());
159         * const_cast<typename iterator_value<Base>::type *>(
160             (m_input.m_next_available++)
161         ) = c;
162         // if input buffer is full - we're done for now
163         if(m_input.m_buffer.end() == m_input.m_next_available)
164             break;
165     }
166     const typename boost::iterators::iterator_value<Base>::type * input_new_start;
167     typename iterator_value<this_t>::type * next_available;
168
169     BOOST_ATTRIBUTE_UNUSED // redundant with ignore_unused below but clarifies intention
170     std::codecvt_base::result r = m_codecvt_facet.in(
171         m_mbs,
172         m_input.m_buffer.begin(),
173         m_input.m_next_available,
174         input_new_start,
175         m_output.m_buffer.begin(),
176         m_output.m_buffer.end(),
177         next_available
178     );
179     BOOST_ASSERT(std::codecvt_base::ok == r);
180     m_output.m_next_available = next_available;
181     m_output.m_next = m_output.m_buffer.begin();
182
183     // we're done with some of the input so shift left.
184     m_input.m_next_available = std::copy(
185         input_new_start,
186         m_input.m_next_available,
187         m_input.m_buffer.begin()
188     );
189     m_input.m_next = m_input.m_buffer.begin();
190 }
191
192 } // namespace iterators
193 } // namespace archive
194 } // namespace boost
195
196 #endif // BOOST_ARCHIVE_ITERATORS_WCHAR_FROM_MB_HPP