finite_state_filter.hpp 11 KB

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