読者です 読者をやめる 読者になる 読者になる

堕(惰)プログラマ開発記録

タイトル変えようかなとも思ってるけれど,思い浮かばない

Boost.Spirit.X3のrepeat directiveっぽいの

Boost C++

有るのか無いのかよくわからなかった*1ので,Boost.Spirit.X3用のrepeatをkleeneを参考にしながら書いてみた*2
一応本家のコードではinclude文がコメントアウトされてるよね.

これだとinfみたいな指定もできないよね?みたいな問題もあったりすると思うんだけれど, "std::numeric_limits::max" で誤魔化せるよきっと.
テストを適当にしかやってないから,ご利用は計画的に.

一応,Qiのrepeat*3相当の使い方として,次の2通りについてサポートしています. repeat[a] は kleene(要は*) を使ってねってことで.

  • repeat(n)[a]
  • repeat(min, max)[a]

さて,以下がコード.(Gistとかに上げたほうがいいのかな?)

#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/range/iterator_range.hpp>

namespace boost { namespace spirit { namespace x3
{
    template <typename Subject, typename Derived, typename T>
    struct repeat_value_holder
      : unary_parser<Subject, Derived>
    {
        typedef unary_parser<Subject, Derived> base_type;
        mutable T min, max;
        repeat_value_holder(Subject const& subject, T const& min, T const& max)
          : base_type(subject)
          , min(min)
          , max(max) {}
    };

    template <typename Subject, typename Derived, typename T>
    struct repeat_value_holder<Subject, Derived, T const>
      : unary_parser<Subject, Derived>
    {
        typedef unary_parser<Subject, Derived> base_type;
        T min, max;

        repeat_value_holder(Subject const& subject, T const& min, T const& max)
          : base_type(subject)
          , min(min)
          , max(max) {}
    };

    template <typename Subject, typename T>
    struct repeat_directive
      : repeat_value_holder<Subject, repeat_directive<Subject, T>, T>
    {
        typedef repeat_value_holder<Subject, repeat_directive<Subject, T>, T> base_type;
        static bool const handles_container = true;
        typedef Subject subject_type;

        repeat_directive(Subject const& subject, T const& min, T const& max)
          : base_type(subject, min, max) {}

        template <typename Iterator, typename Context
            , typename RContext, typename Attribute>
        bool parse(Iterator& first, Iterator const& last
          , Context const& context, RContext& rcontext, Attribute& attr) const
        {
            typename std::remove_const<T>::type num = 0;

            while(num < this->max && detail::parse_into_container(
                this->subject, first, last, context, rcontext, attr))
            {
                ++num;
            }

            return num >= this->min && num <= this->max;
        }
    };

    template <typename T>
    struct repeat_gen
    {
        T& min;
        T& max;

        repeat_gen(T& adjust)
          : min(adjust), max(adjust) {}

        repeat_gen(T& min, T& max)
          : min(min), max(max) {}

        template <typename Subject>
        repeat_directive<typename extension::as_parser<Subject>::value_type, T>
        operator[](Subject const& subject) const
        {
            return {as_parser(subject), min, max};
        }
    };

    template <typename T>
    inline repeat_gen<T> repeat(T& adjust)
    {
        return repeat_gen<T>{adjust};
    }

    template <typename T>
    inline repeat_gen<T const> repeat(T const& adjust)
    {
        return repeat_gen<T const>{adjust};
    }

    template <typename T>
    inline repeat_gen<T> repeat(T& min, T& max)
    {
        return repeat_gen<T>{min, max};
    }

    template <typename T>
    inline repeat_gen<T const> repeat(T const& min, T const& max)
    {
        return repeat_gen<T const>{min, max};
    }
}}}

こうしたほうがいいんじゃない?みたいなご意見有りましたら適当にどうぞ

余談

微熱で結構怠い
→論文読んだりしたくない
→というか,頭使いたくない
C++書こう.

*1:Spirit.Qiと被って,非常にググラビリティ低いしなぁ

*2:先週末ぐらいに書いたんだっけ?

*3:http://www.boost.org/doc/libs/1_57_0/libs/spirit/doc/html/spirit/qi/reference/directive/repeat.html