// (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 #include // EOF. #include // cin, cout. #include #include #include // JOIN, member template friends. #include #include #include #include // put_if. #include #include // openmode. #include #include #include #include #include #include #include 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 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 \ 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 struct finite_state_machine_base_ex : finite_state_machine_base { template struct is { static bool test(Ch event, const std::locale&) { return event == C; } }; }; //------------------Definition of base class for finite state filters---------// namespace detail { template class finite_state_filter_impl; } // End namespace detail. template class finite_state_machine : public finite_state_machine_base_ex { public: typedef Ch char_type; typedef typename char_traits::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 void _push_impl(Ch c) { push(c); } #endif #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS template friend class detail::finite_state_filter_impl; #else public: #endif void on_any(char_type) { } private: typedef std::basic_string 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 \ void push(Ch c) \ { ::boost::iostreams::finite_state_machine::push(c); } \ template \ 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 class finite_state_filter_impl : protected FiniteStateMachine { private: template struct process_event_impl; public: typedef typename char_type_of::type char_type; finite_state_filter_impl() : state_(FiniteStateMachine::initial_state) { } template explicit finite_state_filter_impl(const T0& t0) : FiniteStateMachine(t0), state_(FiniteStateMachine::initial_state) { } template finite_state_filter_impl(const T0& t0, const T1& t1) : FiniteStateMachine(t0, t1), state_(FiniteStateMachine::initial_state) { } template 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::type first; typedef typename mpl::end::type last; state_ = process_event_impl::execute(*this, state_, c); } int& state() { return state_; } void reset() { state_ = FiniteStateMachine::initial_state; this->clear(); } private: template struct process_event_impl { static int execute(FiniteStateMachine& fsm, int state, char_type event) { typedef typename mpl::deref::type rule; typedef typename mpl::next::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::execute(fsm, state, event); } }; template struct process_event_impl { 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 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 class finite_state_filter : public detail::finite_state_filter_impl { private: typedef detail::finite_state_filter_impl base_type; public: typedef typename base_type::char_type char_type; typedef char_traits 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 finite_state_filter(const T0& t0) : base_type(t0), flags_(0) { } template finite_state_filter(const T0& t0, const T1& t1) : base_type(t0, t1), flags_(0) { } template finite_state_filter(const T0& t0, const T1& t1, const T2& t2) : base_type(t0, t1, t2), flags_(0) { } template 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 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 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