123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
- // (C) Copyright 2005-2007 Jonathan Turkanis
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
- // See http://www.boost.org/libs/iostreams for documentation.
- // Adapted from an example of James Kanze, with suggestions from Peter Dimov.
- // See https://web.archive.org/web/20041222094942/http://www.gabi-soft.fr/codebase-en.html.
- #ifndef BOOST_IOSTREAMS_FINITE_STATE_FILTER_HPP_INCLUDED
- #define BOOST_IOSTREAMS_FINITE_STATE_FILTER_HPP_INCLUDED
- #include <cassert>
- #include <cstdio> // EOF.
- #include <iostream> // cin, cout.
- #include <locale>
- #include <string>
- #include <boost/config.hpp> // JOIN, member template friends.
- #include <boost/detail/workaround.hpp>
- #include <boost/iostreams/categories.hpp>
- #include <boost/iostreams/char_traits.hpp>
- #include <boost/iostreams/checked_operations.hpp> // put_if.
- #include <boost/iostreams/concepts.hpp>
- #include <boost/iostreams/detail/ios.hpp> // openmode.
- #include <boost/iostreams/filter/stdio.hpp>
- #include <boost/iostreams/operations.hpp>
- #include <boost/mpl/begin_end.hpp>
- #include <boost/mpl/deref.hpp>
- #include <boost/preprocessor/control/expr_if.hpp>
- #include <boost/static_assert.hpp>
- #include <boost/type_traits/is_base_and_derived.hpp>
- namespace boost { namespace iostreams {
- //------------------Definition of basic character classes---------------------//
- struct finite_state_machine_base {
- static const int initial_state = 0;
- // All-inclusive character class.
- struct is_any {
- template<typename Ch>
- static bool test(Ch, const std::locale&) { return true; }
- };
- // Locale-sensitive character classes.
- #define BOOST_IOSTREAMS_CHARACTER_CLASS(class) \
- struct BOOST_JOIN(is_, class) { \
- template<typename Ch> \
- static bool test(Ch event, const std::locale& loc) \
- { return std::BOOST_JOIN(is, class)(event, loc); } \
- }; \
- /**/
- BOOST_IOSTREAMS_CHARACTER_CLASS(alnum)
- BOOST_IOSTREAMS_CHARACTER_CLASS(alpha)
- BOOST_IOSTREAMS_CHARACTER_CLASS(cntrl)
- BOOST_IOSTREAMS_CHARACTER_CLASS(digit)
- BOOST_IOSTREAMS_CHARACTER_CLASS(graph)
- BOOST_IOSTREAMS_CHARACTER_CLASS(lower)
- BOOST_IOSTREAMS_CHARACTER_CLASS(print)
- BOOST_IOSTREAMS_CHARACTER_CLASS(punct)
- BOOST_IOSTREAMS_CHARACTER_CLASS(space)
- BOOST_IOSTREAMS_CHARACTER_CLASS(upper)
- BOOST_IOSTREAMS_CHARACTER_CLASS(xdigit)
- #undef BOOST_IOSTREAMS_CHARACTER_CLASS
- };
- template<typename Ch>
- struct finite_state_machine_base_ex : finite_state_machine_base {
- template<Ch C>
- struct is {
- static bool test(Ch event, const std::locale&)
- {
- return event == C;
- }
- };
- };
- //------------------Definition of base class for finite state filters---------//
- namespace detail {
- template<typename FiniteStateMachine>
- class finite_state_filter_impl;
- } // End namespace detail.
- template<typename Derived, typename Ch = char>
- class finite_state_machine : public finite_state_machine_base_ex<Ch> {
- public:
- typedef Ch char_type;
- typedef typename char_traits<Ch>::int_type int_type;
- void imbue(const std::locale& loc) { loc_ = loc; }
- const std::locale& getloc() const { return loc_; }
- protected:
- finite_state_machine() : off_(0) { }
- // Template whose instantiations make up transition table.
- template< int State,
- typename CharacterClass,
- int NextState,
- void (Derived::*Action)(char_type) >
- struct row {
- typedef CharacterClass character_class;
- static const int state = State;
- static const int next_state = NextState;
- static void execute(Derived& d, char_type event)
- {
- (d.*Action)(event);
- }
- };
- // Stack interface.
- bool empty() const
- {
- return off_ == buf_.size();
- }
- void push(char c) { buf_ += c; }
- char_type pop()
- {
- char_type result = buf_[off_++];
- if (off_ == buf_.size())
- clear();
- return result;
- }
- char_type& top() { return buf_[off_]; }
- void clear()
- {
- buf_.clear();
- off_ = 0;
- }
- // Default event handlers.
- void on_eof() { }
- void skip(char_type) { }
- #if BOOST_WORKAROUND(__MWERKS__, <= 0x3206)
- template<typename Ch>
- void _push_impl(Ch c) { push(c); }
- #endif
- #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
- template<typename FiniteStateFilter>
- friend class detail::finite_state_filter_impl;
- #else
- public:
- #endif
- void on_any(char_type) { }
- private:
- typedef std::basic_string<char_type> string_type;
- typedef typename string_type::size_type size_type;
- std::locale loc_;
- string_type buf_;
- size_type off_;
- };
- #if !BOOST_WORKAROUND(__MWERKS__, <= 0x3206)
- # define BOOST_IOSTREAMS_FSM(fsm) \
- template<typename Ch> \
- void push(Ch c) \
- { ::boost::iostreams::finite_state_machine<fsm, Ch>::push(c); } \
- template<typename Ch> \
- void skip(Ch c) { (void) c; } \
- /**/
- #else // #ifndef __MWERKS__
- # define BOOST_IOSTREAMS_FSM(fsm) \
- void push(char c) { this->_push_impl(c); } \
- void push(wchar_t c) { this->_push_impl(c); } \
- void skip(char c) { (void) c; } \
- void skip(wchar_t c) { (void) c; } \
- /**/
- #endif
- //------------------Definition of finite_state_filter_impl--------------------//
- namespace detail {
- template<typename FiniteStateMachine>
- class finite_state_filter_impl : protected FiniteStateMachine
- {
- private:
- template<typename First, typename Last>
- struct process_event_impl;
- public:
- typedef typename char_type_of<FiniteStateMachine>::type char_type;
- finite_state_filter_impl() : state_(FiniteStateMachine::initial_state) { }
- template<typename T0>
- explicit finite_state_filter_impl(const T0& t0)
- : FiniteStateMachine(t0), state_(FiniteStateMachine::initial_state)
- { }
- template<typename T0, typename T1>
- finite_state_filter_impl(const T0& t0, const T1& t1)
- : FiniteStateMachine(t0, t1), state_(FiniteStateMachine::initial_state)
- { }
- template<typename T0, typename T1, typename T2>
- finite_state_filter_impl(const T0& t0, const T1& t1, const T2& t2)
- : FiniteStateMachine(t0, t1, t2),
- state_(FiniteStateMachine::initial_state)
- { }
- protected:
- void process_event(char_type c)
- {
- typedef typename FiniteStateMachine::transition_table transitions;
- typedef typename mpl::begin<transitions>::type first;
- typedef typename mpl::end<transitions>::type last;
- state_ = process_event_impl<first, last>::execute(*this, state_, c);
- }
- int& state() { return state_; }
- void reset()
- {
- state_ = FiniteStateMachine::initial_state;
- this->clear();
- }
- private:
- template<typename First, typename Last>
- struct process_event_impl {
- static int execute(FiniteStateMachine& fsm, int state, char_type event)
- {
- typedef typename mpl::deref<First>::type rule;
- typedef typename mpl::next<First>::type next;
- typedef typename rule::character_class character_class;
- if ( state == rule::state &&
- character_class::test(event, fsm.getloc()) )
- {
- // Rule applies.
- rule::execute(fsm, event);
- return rule::next_state;
- }
- // Rule is inapplicable: try next rule.
- return process_event_impl<next, Last>::execute(fsm, state, event);
- }
- };
- template<typename Last>
- struct process_event_impl<Last, Last> {
- static int execute(FiniteStateMachine& fsm, int state, char_type c)
- {
- on_any(fsm, c);
- return state;
- }
- };
- #if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) /* Tru64 */ \
- || BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3205)) /* CW9.4 */
- public:
- #endif
- template<typename FSM>
- static void on_any(FSM& fsm, char_type c) { fsm.on_any(c); }
- private:
- int state_;
- };
- } // End namespace detail.
- //------------------Definition of finite_state_filter-------------------------//
- template<typename FiniteStateMachine>
- class finite_state_filter
- : public detail::finite_state_filter_impl<FiniteStateMachine>
- {
- private:
- typedef detail::finite_state_filter_impl<FiniteStateMachine> base_type;
- public:
- typedef typename base_type::char_type char_type;
- typedef char_traits<char_type> traits_type;
- typedef typename base_type::int_type int_type;
- struct category
- : dual_use, filter_tag, closable_tag, localizable_tag
- { };
- finite_state_filter() : flags_(0) { }
- template<typename T0>
- finite_state_filter(const T0& t0)
- : base_type(t0), flags_(0)
- { }
- template<typename T0, typename T1>
- finite_state_filter(const T0& t0, const T1& t1)
- : base_type(t0, t1), flags_(0)
- { }
- template<typename T0, typename T1, typename T2>
- finite_state_filter(const T0& t0, const T1& t1, const T2& t2)
- : base_type(t0, t1, t2), flags_(0)
- { }
- template<typename Source>
- int_type get(Source& src)
- {
- assert((flags_ & f_write) == 0);
- flags_ |= f_read;
- while (true) {
- if ((flags_ & f_eof) == 0) {
- // Read a character and process it.
- int_type c;
- if (traits_type::is_eof(c = iostreams::get(src))) {
- flags_ |= f_eof;
- this->on_eof();
- } else if (!traits_type::would_block(c)) {
- this->process_event(c);
- }
- }
- // Return a character, if available.
- if (!this->empty())
- return this->pop();
- else if ((flags_ & f_eof) != 0)
- return traits_type::eof();
- }
- }
- template<typename Sink>
- bool put(Sink& dest, char_type c)
- {
- assert((flags_ & f_read) == 0);
- flags_ |= f_write;
- this->process_event(c);
- while (!this->empty() && iostreams::put(dest, this->top()))
- this->pop();
- return true;
- }
- template<typename Device>
- void close(Device& dev, BOOST_IOS::openmode which)
- {
- if (which == BOOST_IOS::out) {
- if (flags_ & f_write)
- while (!this->empty())
- iostreams::put_if(dev, this->pop());
- this->reset();
- flags_ = 0;
- }
- }
- private:
- enum flags {
- f_read = 1,
- f_write = f_read << 1,
- f_eof = f_write << 1
- };
- int flags_;
- };
- } } // End namespaces iostreams, boost.
- #endif // #ifndef BOOST_IOSTREAMS_FINITE_STATE_FILTER_HPP_INCLUDED
|