Sprout::Weed の lim を短くする
特定の文字列をパースする場合に Sprout::Weed の lim を使用して
*w::lim<4>(w::char_ - ':') >> ":" >> *w::lim<2>(w::char_)
の様なパーサを定義するんですが、これだと若干長くなってしまいます。
これはこれで汎用性があっていいのですが、簡単なパーサを定義する場合はちょっとめんどくさいよねー、ってことどうにかして短く出来ないかとやってみました。
[ソース]
#include <sprout/weed.hpp> template<typename Parser, typename Category, std::size_t Size> struct limiter_impl : sprout::weed::parser_base{ template<typename Context, typename Iterator> struct attribute{ typedef decltype( sprout::weed::parse( std::declval<Iterator>(), std::declval<Iterator>(), sprout::weed::lim<Size>(std::declval<Parser>()) ).attr() ) type; }; template<typename Context, typename Iterator> struct result{ typedef sprout::weed::parser_result<Iterator, typename attribute<Context, Iterator>::type> type; }; constexpr limiter_impl() = default; explicit constexpr limiter_impl(Parser const& parser, Category const& category) : parser_(parser), category_(category){} template< typename Context, typename Iterator, typename Result = typename result<Context, Iterator>::type > constexpr Result operator()( Iterator first, Iterator last, Context const& ) const{ return eval<Result>(sprout::weed::parse(first, last, sprout::weed::lim<Size>(parser_, category_))); } template<typename Result, typename Parsed> constexpr Result eval(Parsed&& parsed) const{ return Result{ parsed.success(), parsed.current(), parsed.attr() }; } constexpr sprout::weed::limited::category category() const{ return category_; } constexpr Parser parser() const{ return parser_; } private: Parser parser_; Category category_; }; // // operator* // template<typename Parser, typename Category, std::size_t Size> constexpr auto operator *(::limiter_impl<Parser, Category, Size> const& lim) ->decltype(*sprout::weed::lim<Size>(lim.parser(), lim.category())) const{ return *sprout::weed::lim<Size>(lim.parser(), lim.category()); } template<typename Parser, typename Category, std::size_t Size> constexpr auto operator *(::limiter_impl<Parser, Category, Size>&& lim) ->decltype(*sprout::weed::lim<Size>(lim.parser(), lim.category())) const{ return *sprout::weed::lim<Size>(lim.parser(), lim.category()); } // // operator - // template<typename Parser, typename Category, std::size_t Size, typename T> constexpr auto operator -(::limiter_impl<Parser, Category, Size> const& lim, T&& t) ->decltype(sprout::weed::lim<Size>(lim.parser() - t, lim.category())) const{ return sprout::weed::lim<Size>(lim.parser() - t, lim.category()); } template<typename Parser, typename Category, std::size_t Size, typename T> constexpr auto operator -(::limiter_impl<Parser, Category, Size>&& lim, T&& t) ->decltype(sprout::weed::lim<Size>(lim.parser() - t, lim.category())) const{ return sprout::weed::lim<Size>(lim.parser() - t, lim.category()); } // // operator >> // template<typename Parser, typename Category, std::size_t Size, typename T> constexpr auto operator >>(::limiter_impl<Parser, Category, Size> const& lim, T&& t) ->decltype(sprout::weed::lim<Size>(lim.parser() >> t, lim.category())) const{ return sprout::weed::lim<Size>(lim.parser() >> t, lim.category()); } template<typename Parser, typename Category, std::size_t Size, typename T> constexpr auto operator >>(::limiter_impl<Parser, Category, Size>&& lim, T&& t) ->decltype(sprout::weed::lim<Size>(lim.parser() >> t, lim.category())) const{ return sprout::weed::lim<Size>(lim.parser() >> t, lim.category()); } template<std::size_t N, typename Parser, typename Category, typename Result = limiter_impl<typename std::decay<Parser>::type, typename std::decay<Category>::type, N> > constexpr Result limiter(Parser&& parser, Category&& category){ return Result{ sprout::forward<Parser>(parser), sprout::forward<Category>(category) }; } template<std::size_t Size> constexpr auto chars() ->decltype(limiter<Size>(sprout::weed::char_, sprout::weed::limited::discard)){ return limiter<Size>(sprout::weed::char_, sprout::weed::limited::discard); } template<std::size_t Size, typename Category> constexpr auto chars(Category&& category) ->decltype(limiter<Size>(sprout::weed::char_, sprout::forward<Category>(category))){ return limiter<Size>(sprout::weed::char_, sprout::forward<Category>(category)); } static constexpr auto char1 = chars<1>(); static constexpr auto char2 = chars<2>(); static constexpr auto char3 = chars<3>(); static constexpr auto char4 = chars<4>(); static constexpr auto char5 = chars<5>(); static constexpr auto char6 = chars<6>(); static constexpr auto char7 = chars<7>(); static constexpr auto char8 = chars<8>(); static constexpr auto char9 = chars<9>(); static constexpr auto char10 = chars<10>(); template<typename Parsed> struct parsed_holder{ constexpr operator bool() const{ return parsed.success(); } constexpr decltype(std::declval<Parsed>().attr()) attr() const{ return parsed.attr(); } template<typename T> constexpr bool operator ==(T const& t) const{ return parsed.attr() == t; } template<typename T> constexpr bool operator ==(parsed_holder<T> const& t) const{ return attr() == t.attr(); } Parsed parsed; }; template<typename Char, std::size_t N, typename Parser> constexpr auto parse(Char const(&str)[N], Parser&& parser) ->parsed_holder<decltype( sprout::weed::parse(str, str+N-1, sprout::forward<Parser>(parser)) )>{ return { sprout::weed::parse(str, str+N-1, sprout::forward<Parser>(parser)) }; } int main(){ namespace w = sprout::weed; // w::lim を使用する場合長くなってしまう static_assert(parse("homu:an", *w::lim<4>(w::char_ - ':') >> ":" >> *w::lim<2>(w::char_)) == "homuan", ""); // 短い! static_assert(parse("homu:an", *(char4 - ':') >> ":" >> *char2) == "homuan", ""); { static constexpr char src[] = "homumado"; static_assert(parse(src, chars<4>()), ""); static_assert(parse(src, chars<4>()) == 'h', ""); static_assert(parse(src, chars<4>()) == parse(src, w::lim<4>(w::char_)), ""); static_assert(parse(src, *chars<4>()), ""); static_assert(parse(src, *chars<4>()) == "homu", ""); static_assert(parse(src, *w::lim<4>(w::char_)), ""); static_assert(parse(src, *chars<4>()) == parse(src, *w::lim<4>(w::char_)), ""); static_assert(parse(src, *chars<4>(w::limited::circular)) == "mado", ""); static_assert( parse(src, *chars<4>(w::limited::circular)) == parse(src, *w::lim<4>(w::char_, w::limited::circular)), ""); static_assert(parse(src, chars<4>() - 'm') == parse(src, w::lim<4>(w::char_ - 'm')), ""); static_assert(parse(src, *(chars<4>() - 'm')) == parse(src, *w::lim<4>(w::char_ - 'm')), ""); static_assert( parse(src, "homu" >> *chars<4>()) == parse(src, "homu" >> *w::lim<4>(w::char_)) , ""); } return 0; }
ちょっとコードは長いですが、要は
*(char4 - ':') == *lim<4>(char_ - ':')
が等価になるようなパーサを定義しているだけですね。
まだ operator << と operator - しか定義していませんが、そこそこ使えるんじゃないかと。
個人的にはパーサがだいぶすっきりしていて気に入っているんですがどうでしょう。
あとどうでもいいですが、T&& が厄介過ぎて辛い。
多重定義と相性が悪すぎる…。