1// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2// (C) Copyright 2005-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// Adapted from an example of James Kanze, with suggestions from Peter Dimov.
9// See https://web.archive.org/web/20041222094942/http://www.gabi-soft.fr/codebase-en.html.
10
11#ifndef BOOST_IOSTREAMS_FINITE_STATE_FILTER_HPP_INCLUDED
12#define BOOST_IOSTREAMS_FINITE_STATE_FILTER_HPP_INCLUDED
13
14#include <cassert>
15#include <cstdio> // EOF.
16#include <iostream> // cin, cout.
17#include <locale>
18#include <string>
19#include <boost/config.hpp> // JOIN, member template friends.
20#include <boost/detail/workaround.hpp>
21#include <boost/iostreams/categories.hpp>
22#include <boost/iostreams/char_traits.hpp>
23#include <boost/iostreams/checked_operations.hpp> // put_if.
24#include <boost/iostreams/concepts.hpp>
25#include <boost/iostreams/detail/ios.hpp> // openmode.
26#include <boost/iostreams/filter/stdio.hpp>
27#include <boost/iostreams/operations.hpp>
28#include <boost/mpl/begin_end.hpp>
29#include <boost/mpl/deref.hpp>
30#include <boost/preprocessor/control/expr_if.hpp>
31#include <boost/static_assert.hpp>
32#include <boost/type_traits/is_base_and_derived.hpp>
33
34namespace boost { namespace iostreams {
35
36//------------------Definition of basic character classes---------------------//
37
38struct finite_state_machine_base {
39
40 static const int initial_state = 0;
41
42 // All-inclusive character class.
43
44 struct is_any {
45 template<typename Ch>
46 static bool test(Ch, const std::locale&) { return true; }
47 };
48
49 // Locale-sensitive character classes.
50
51 #define BOOST_IOSTREAMS_CHARACTER_CLASS(class) \
52 struct BOOST_JOIN(is_, class) { \
53 template<typename Ch> \
54 static bool test(Ch event, const std::locale& loc) \
55 { return std::BOOST_JOIN(is, class)(event, loc); } \
56 }; \
57 /**/
58
59 BOOST_IOSTREAMS_CHARACTER_CLASS(alnum)
60 BOOST_IOSTREAMS_CHARACTER_CLASS(alpha)
61 BOOST_IOSTREAMS_CHARACTER_CLASS(cntrl)
62 BOOST_IOSTREAMS_CHARACTER_CLASS(digit)
63 BOOST_IOSTREAMS_CHARACTER_CLASS(graph)
64 BOOST_IOSTREAMS_CHARACTER_CLASS(lower)
65 BOOST_IOSTREAMS_CHARACTER_CLASS(print)
66 BOOST_IOSTREAMS_CHARACTER_CLASS(punct)
67 BOOST_IOSTREAMS_CHARACTER_CLASS(space)
68 BOOST_IOSTREAMS_CHARACTER_CLASS(upper)
69 BOOST_IOSTREAMS_CHARACTER_CLASS(xdigit)
70
71 #undef BOOST_IOSTREAMS_CHARACTER_CLASS
72};
73
74template<typename Ch>
75struct finite_state_machine_base_ex : finite_state_machine_base {
76 template<Ch C>
77 struct is {
78 static bool test(Ch event, const std::locale&)
79 {
80 return event == C;
81 }
82 };
83};
84
85//------------------Definition of base class for finite state filters---------//
86
87namespace detail {
88
89template<typename FiniteStateMachine>
90class finite_state_filter_impl;
91
92} // End namespace detail.
93
94template<typename Derived, typename Ch = char>
95class finite_state_machine : public finite_state_machine_base_ex<Ch> {
96public:
97 typedef Ch char_type;
98 typedef typename char_traits<Ch>::int_type int_type;
99 void imbue(const std::locale& loc) { loc_ = loc; }
100 const std::locale& getloc() const { return loc_; }
101protected:
102 finite_state_machine() : off_(0) { }
103
104 // Template whose instantiations make up transition table.
105
106 template< int State,
107 typename CharacterClass,
108 int NextState,
109 void (Derived::*Action)(char_type) >
110 struct row {
111 typedef CharacterClass character_class;
112 static const int state = State;
113 static const int next_state = NextState;
114 static void execute(Derived& d, char_type event)
115 {
116 (d.*Action)(event);
117 }
118 };
119
120 // Stack interface.
121
122 bool empty() const
123 {
124 return off_ == buf_.size();
125 }
126 void push(char c) { buf_ += c; }
127 char_type pop()
128 {
129 char_type result = buf_[off_++];
130 if (off_ == buf_.size())
131 clear();
132 return result;
133 }
134 char_type& top() { return buf_[off_]; }
135 void clear()
136 {
137 buf_.clear();
138 off_ = 0;
139 }
140
141 // Default event handlers.
142
143 void on_eof() { }
144 void skip(char_type) { }
145
146#if BOOST_WORKAROUND(__MWERKS__, <= 0x3206)
147 template<typename Ch>
148 void _push_impl(Ch c) { push(c); }
149#endif
150
151#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
152 template<typename FiniteStateFilter>
153 friend class detail::finite_state_filter_impl;
154#else
155 public:
156#endif
157 void on_any(char_type) { }
158private:
159 typedef std::basic_string<char_type> string_type;
160 typedef typename string_type::size_type size_type;
161 std::locale loc_;
162 string_type buf_;
163 size_type off_;
164};
165
166#if !BOOST_WORKAROUND(__MWERKS__, <= 0x3206)
167# define BOOST_IOSTREAMS_FSM(fsm) \
168 template<typename Ch> \
169 void push(Ch c) \
170 { ::boost::iostreams::finite_state_machine<fsm, Ch>::push(c); } \
171 template<typename Ch> \
172 void skip(Ch c) { (void) c; } \
173 /**/
174#else // #ifndef __MWERKS__
175# define BOOST_IOSTREAMS_FSM(fsm) \
176 void push(char c) { this->_push_impl(c); } \
177 void push(wchar_t c) { this->_push_impl(c); } \
178 void skip(char c) { (void) c; } \
179 void skip(wchar_t c) { (void) c; } \
180 /**/
181#endif
182
183//------------------Definition of finite_state_filter_impl--------------------//
184
185namespace detail {
186
187template<typename FiniteStateMachine>
188class finite_state_filter_impl : protected FiniteStateMachine
189{
190private:
191 template<typename First, typename Last>
192 struct process_event_impl;
193public:
194 typedef typename char_type_of<FiniteStateMachine>::type char_type;
195
196 finite_state_filter_impl() : state_(FiniteStateMachine::initial_state) { }
197
198 template<typename T0>
199 explicit finite_state_filter_impl(const T0& t0)
200 : FiniteStateMachine(t0), state_(FiniteStateMachine::initial_state)
201 { }
202
203 template<typename T0, typename T1>
204 finite_state_filter_impl(const T0& t0, const T1& t1)
205 : FiniteStateMachine(t0, t1), state_(FiniteStateMachine::initial_state)
206 { }
207
208 template<typename T0, typename T1, typename T2>
209 finite_state_filter_impl(const T0& t0, const T1& t1, const T2& t2)
210 : FiniteStateMachine(t0, t1, t2),
211 state_(FiniteStateMachine::initial_state)
212 { }
213protected:
214 void process_event(char_type c)
215 {
216 typedef typename FiniteStateMachine::transition_table transitions;
217 typedef typename mpl::begin<transitions>::type first;
218 typedef typename mpl::end<transitions>::type last;
219 state_ = process_event_impl<first, last>::execute(*this, state_, c);
220 }
221 int& state() { return state_; }
222 void reset()
223 {
224 state_ = FiniteStateMachine::initial_state;
225 this->clear();
226 }
227private:
228 template<typename First, typename Last>
229 struct process_event_impl {
230 static int execute(FiniteStateMachine& fsm, int state, char_type event)
231 {
232 typedef typename mpl::deref<First>::type rule;
233 typedef typename mpl::next<First>::type next;
234 typedef typename rule::character_class character_class;
235
236 if ( state == rule::state &&
237 character_class::test(event, fsm.getloc()) )
238 {
239 // Rule applies.
240 rule::execute(fsm, event);
241 return rule::next_state;
242 }
243
244 // Rule is inapplicable: try next rule.
245 return process_event_impl<next, Last>::execute(fsm, state, event);
246 }
247 };
248
249 template<typename Last>
250 struct process_event_impl<Last, Last> {
251 static int execute(FiniteStateMachine& fsm, int state, char_type c)
252 {
253 on_any(fsm, c);
254 return state;
255 }
256 };
257#if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) /* Tru64 */ \
258 || BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3205)) /* CW9.4 */
259 public:
260#endif
261 template<typename FSM>
262 static void on_any(FSM& fsm, char_type c) { fsm.on_any(c); }
263private:
264 int state_;
265};
266
267} // End namespace detail.
268
269//------------------Definition of finite_state_filter-------------------------//
270
271template<typename FiniteStateMachine>
272class finite_state_filter
273 : public detail::finite_state_filter_impl<FiniteStateMachine>
274{
275private:
276 typedef detail::finite_state_filter_impl<FiniteStateMachine> base_type;
277public:
278 typedef typename base_type::char_type char_type;
279 typedef char_traits<char_type> traits_type;
280 typedef typename base_type::int_type int_type;
281 struct category
282 : dual_use, filter_tag, closable_tag, localizable_tag
283 { };
284
285 finite_state_filter() : flags_(0) { }
286
287 template<typename T0>
288 finite_state_filter(const T0& t0)
289 : base_type(t0), flags_(0)
290 { }
291
292 template<typename T0, typename T1>
293 finite_state_filter(const T0& t0, const T1& t1)
294 : base_type(t0, t1), flags_(0)
295 { }
296
297 template<typename T0, typename T1, typename T2>
298 finite_state_filter(const T0& t0, const T1& t1, const T2& t2)
299 : base_type(t0, t1, t2), flags_(0)
300 { }
301
302 template<typename Source>
303 int_type get(Source& src)
304 {
305 assert((flags_ & f_write) == 0);
306 flags_ |= f_read;
307
308 while (true) {
309 if ((flags_ & f_eof) == 0) {
310
311 // Read a character and process it.
312 int_type c;
313 if (traits_type::is_eof(c = iostreams::get(src))) {
314 flags_ |= f_eof;
315 this->on_eof();
316 } else if (!traits_type::would_block(c)) {
317 this->process_event(c);
318 }
319 }
320
321 // Return a character, if available.
322 if (!this->empty())
323 return this->pop();
324 else if ((flags_ & f_eof) != 0)
325 return traits_type::eof();
326 }
327 }
328
329 template<typename Sink>
330 bool put(Sink& dest, char_type c)
331 {
332 assert((flags_ & f_read) == 0);
333 flags_ |= f_write;
334
335 this->process_event(c);
336 while (!this->empty() && iostreams::put(dest, this->top()))
337 this->pop();
338
339 return true;
340 }
341
342 template<typename Device>
343 void close(Device& dev, BOOST_IOS::openmode which)
344 {
345 if (which == BOOST_IOS::out) {
346 if (flags_ & f_write)
347 while (!this->empty())
348 iostreams::put_if(dev, this->pop());
349 this->reset();
350 flags_ = 0;
351 }
352 }
353private:
354 enum flags {
355 f_read = 1,
356 f_write = f_read << 1,
357 f_eof = f_write << 1
358 };
359
360 int flags_;
361};
362
363} } // End namespaces iostreams, boost.
364
365#endif // #ifndef BOOST_IOSTREAMS_FINITE_STATE_FILTER_HPP_INCLUDED
366

source code of boost/libs/iostreams/example/finite_state_filter.hpp