Parsing vectors of shared_ptr to base class

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Parsing vectors of shared_ptr to base class

Mario Lang
Hi.

I just realized I can parse heterogenous containers of pointers to base
classes with something like this:

#if !defined(BMML_SPIRIT_X3_HPP)
#define BMML_SPIRIT_X3_HPP

#include <boost/spirit/home/x3.hpp>

namespace bmml {
  namespace spirit {
    inline namespace x3 {
      template<typename T>
      struct dynamic_pointer_parser : boost::spirit::x3::parser<
        dynamic_pointer_parser<T>
      > {
        using attribute_type = std::shared_ptr<T>;
        template < typename Iterator, typename Context, typename RContext
                 , typename Attribute>
        bool parse( Iterator& first, Iterator const& last
                  , Context const& context, RContext& rcontext
                  , Attribute& attr) const {
          if (auto val = std::dynamic_pointer_cast<T>(*first)) {
            boost::spirit::x3::traits::move_to(val, attr);
            ++first;

            return true;
          }

          return false;
        }
      };

      template <typename T> dynamic_pointer_parser<T> shared_ptr = {};
    }
  }
}

#endif // !defined(BMML_SPIRIT_X3_HPP)

A small use case might look like this:

#include <fstream>
#include <iostream>
#include <x3.hpp>
#include <bmml.hxx>

using std::begin;
using std::cout;
using bmml::dom::element;
using std::end;
using std::endl;
using bmml::generic_text;
using std::ifstream;
using bmml::newline;
using bmml::spirit::shared_ptr;
using bmml::space;
using std::vector;
namespace x3 = boost::spirit::x3;

int main(int argc, char *argv[]) {
  ifstream file(argv[1]);
  auto score = bmml::parse(file, argv[1]);
  if (auto score_data = score->data()) {
    vector<std::shared_ptr<element>> text;
    auto iter = begin(*score_data);
    if (x3::parse(iter, end(*score_data),
              *(shared_ptr<space> | shared_ptr<newline> | shared_ptr<generic_text>),
              text)) {
      cout << text.size() << " text elements at beginning." << endl;
    }
  }
}

This is going to save me a lot of icky nested conditionals and casts.
And has quite some potential.  I am going to use it a lot with operator%
to parse a nested vector of things separated by specific spearators.
Something I wouldn't want to write with imperative code.
But with this wrapping, spirit can do all the magic.

I wonder if this could be made generic enough to be put into X3 / if
something like this would be useful to others?

Any suggestions for better naming?  I wonder if attribute_type can be
defined properly?
decltype(std::dynamic_pointer_cast<T>(*std::declval<Iterator>())) can
not work because Iterator is not known.

Besides, it does all what I want already.  I can parse casted pointers
into adapted structs, and it will happily do the right thing if
operator| is used on a vector of shared_ptr to a common base.

--
CYa,
  ⡍⠁⠗⠊⠕

------------------------------------------------------------------------------
Transform Data into Opportunity.
Accelerate data analysis in your applications with
Intel Data Analytics Acceleration Library.
Click to learn more.
http://pubads.g.doubleclick.net/gampad/clk?id=278785231&iu=/4140
_______________________________________________
Spirit-general mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/spirit-general
Reply | Threaded
Open this post in threaded view
|

Re: Parsing vectors of shared_ptr to base class

Joel de Guzman
On 20/03/2016 4:08 AM, Mario Lang wrote:

> Hi.
>
> I just realized I can parse heterogenous containers of pointers to base
> classes with something like this:
>
> #if !defined(BMML_SPIRIT_X3_HPP)
> #define BMML_SPIRIT_X3_HPP
>
> #include <boost/spirit/home/x3.hpp>
>
> namespace bmml {
>    namespace spirit {
>      inline namespace x3 {
>        template<typename T>
>        struct dynamic_pointer_parser : boost::spirit::x3::parser<
>          dynamic_pointer_parser<T>
>        > {
>          using attribute_type = std::shared_ptr<T>;
>          template < typename Iterator, typename Context, typename RContext
>                   , typename Attribute>
>          bool parse( Iterator& first, Iterator const& last
>                    , Context const& context, RContext& rcontext
>                    , Attribute& attr) const {
>            if (auto val = std::dynamic_pointer_cast<T>(*first)) {
>              boost::spirit::x3::traits::move_to(val, attr);
>              ++first;
>
>              return true;
>            }
>
>            return false;
>          }
>        };
>
>        template <typename T> dynamic_pointer_parser<T> shared_ptr = {};
>      }
>    }
> }
>
> #endif // !defined(BMML_SPIRIT_X3_HPP)
>
> A small use case might look like this:
>
> #include <fstream>
> #include <iostream>
> #include <x3.hpp>
> #include <bmml.hxx>
>
> using std::begin;
> using std::cout;
> using bmml::dom::element;
> using std::end;
> using std::endl;
> using bmml::generic_text;
> using std::ifstream;
> using bmml::newline;
> using bmml::spirit::shared_ptr;
> using bmml::space;
> using std::vector;
> namespace x3 = boost::spirit::x3;
>
> int main(int argc, char *argv[]) {
>    ifstream file(argv[1]);
>    auto score = bmml::parse(file, argv[1]);
>    if (auto score_data = score->data()) {
>      vector<std::shared_ptr<element>> text;
>      auto iter = begin(*score_data);
>      if (x3::parse(iter, end(*score_data),
>                *(shared_ptr<space> | shared_ptr<newline> | shared_ptr<generic_text>),
>                text)) {
>        cout << text.size() << " text elements at beginning." << endl;
>      }
>    }
> }
>
> This is going to save me a lot of icky nested conditionals and casts.
> And has quite some potential.  I am going to use it a lot with operator%
> to parse a nested vector of things separated by specific spearators.
> Something I wouldn't want to write with imperative code.
> But with this wrapping, spirit can do all the magic.
>
> I wonder if this could be made generic enough to be put into X3 / if
> something like this would be useful to others?
>
> Any suggestions for better naming?  I wonder if attribute_type can be
> defined properly?
> decltype(std::dynamic_pointer_cast<T>(*std::declval<Iterator>())) can
> not work because Iterator is not known.
>
> Besides, it does all what I want already.  I can parse casted pointers
> into adapted structs, and it will happily do the right thing if
> operator| is used on a vector of shared_ptr to a common base.

Hi Mario,

Well, X3 was meant to make it easy for you to write such things. To be honest,
what I prefer more than additional components is documentation on how to
write such things. X3's extension mechanism, if you will.

That said, if there's sufficient interest, I'm very willing to consider adding
more components, not limited to this one. So, if anyone wishes some kind of
component added: 1) Write some code 2) Write some tests 3) Write some docs,
but before anything else, I guess it makes sense to 2.5) Ask if there's interest.

Regards,
--
Joel de Guzman
http://www.ciere.com
http://boost-spirit.com
http://www.cycfi.com/


------------------------------------------------------------------------------
Transform Data into Opportunity.
Accelerate data analysis in your applications with
Intel Data Analytics Acceleration Library.
Click to learn more.
http://pubads.g.doubleclick.net/gampad/clk?id=278785231&iu=/4140
_______________________________________________
Spirit-general mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/spirit-general