On 8/16/2010 2:11 AM, joel falcou wrote:
> On 15/08/10 23:21, Eric Niebler wrote:
>> Haha! I admit I was a bit suspicious at first. Nobody ever said, 
>> "Wow, Proto sped up my compiles!" ;-)
> 
> I wish :)
> 
>> But looking at Joel's implementation, I suspect it can be sped up 
>> considerably by avoiding fusion vectors and maps. (I've found 
>> fusion to be costly at compile time and generally avoid it in 
>> Proto.)
> 
> Yup, same experience here. I dunno if it comes fromthe TMP part of 
> the PP part tough
> 
>> I don't see a reason why the proto expression tree can't directly 
>> serve the same role as the fusion map. Just define a transform 
>> instead of using fusion::at_key.
> 
> Hmmm, how should this transform work ? We already capture the value 
> of the parmaeters by value in the tree so it can actually be used
> for this but I admit the transform is not trivial.

See attached. Not trivial, but not too difficult, either. I haven't run
any (compile-time) perf benchmarks. This captures everything by
reference and should have zero runtime overhead. If compile times are
bad, you of course have the option of replacing composite transforms
with custom primitive ones. Or use precompiled headers, of course.

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com
#include <string>
#include <iostream>
#include <boost/proto/proto.hpp>

namespace boost
{
    using proto::_;

    template<typename Tag>
    struct option
    {
        typedef Tag type;
    };
    
    template<typename Expr>
    struct option_expr;

    struct option_domain
      : proto::domain<proto::pod_generator<option_expr> >
    {};

    struct option_not_found
    {};

    struct OptionTerm
      : proto::terminal<option<_> >
    {};

    struct OptionSpec
      : proto::when<
            proto::assign<OptionTerm, proto::terminal<_> >
          , proto::_value(proto::_right)
        >
    {};

    struct OptionPack
      : proto::or_<
            proto::when<
                proto::comma<OptionPack, OptionSpec>
              , proto::if_<
                    proto::matches<proto::_left(proto::_right), proto::_state>()
                  , OptionSpec(proto::_right)
                  , OptionPack(proto::_left)
                >
            >
          , proto::when<
                OptionSpec
              , proto::if_<
                    proto::matches<proto::_left, proto::_state>()
                  , OptionSpec
                  , option_not_found()
                >
            >
        >
    {};

    template<typename Expr>
    struct option_expr
    {
        BOOST_PROTO_BASIC_EXTENDS(Expr, option_expr, option_domain)
        BOOST_PROTO_EXTENDS_ASSIGN()

        template<typename Sig>
        struct result;

        template<typename Option>
        struct has_option
          : mpl::not_<
                is_same<
                    typename result<option_expr const(Option)>::type
                  , option_not_found
                >
            >
        {};

        template<typename This, typename Option>
        struct result<This(Option)>
          : boost::result_of<OptionPack(This &, Option &)>
        {};

        template<typename This, typename Option, typename Default>
        struct result<This(Option, Default)>
          : mpl::if_<
                has_option<Option>
              , typename result<This(Option)>::type
              , Default
            >
        {};

        template<typename Option>
        typename result<option_expr const(Option const)>::type
        operator()(Option const &opt) const
        {
            BOOST_MPL_ASSERT((proto::matches<Option const, OptionTerm>));
            BOOST_MPL_ASSERT((has_option<Option const>));
            return OptionPack()(*this, opt);
        }

        template<typename Option, typename Default>
        typename result<option_expr const(Option const, Default const)>::type
        operator()(Option const &opt, Default const &def) const
        {
            BOOST_MPL_ASSERT((proto::matches<Option const, , OptionTerm>));
            return this->with_default(opt, def, has_option<Option const>());
        }

    private:
        template<typename Option, typename Default>
        typename result<option_expr const(Option const, Default const)>::type
        with_default(Option const &opt, Default const &, mpl::true_) const
        {
            return OptionPack()(*this, opt);
        }

        template<typename Option, typename Default>
        typename result<option_expr const(Option const, Default const)>::type
        with_default(Option const &, Default const &def, mpl::false_) const
        {
            return def;
        }
    };

    struct options_
    {
        template<typename Opts>
        Opts const &operator[](Opts const &opts) const
        {
            BOOST_MPL_ASSERT((proto::matches<Opts, OptionPack>));
            return opts;
        }
    } options = {};
}

#define BOOST_REGISTER_PARAMETERS(NAME)                         \
    struct NAME ## _ {};                                        \
    boost::option_expr<                                         \
        boost::proto::terminal<boost::option<NAME ## _> >::type \
    > const NAME = {};                                          \
    /**/

////////////////////////////////////////////////////////////////////////////////
// Register some named parameters
////////////////////////////////////////////////////////////////////////////////
namespace tag
{
    BOOST_REGISTER_PARAMETERS(title);
    BOOST_REGISTER_PARAMETERS(pos_x);
    BOOST_REGISTER_PARAMETERS(pos_y);
    BOOST_REGISTER_PARAMETERS(height);
    BOOST_REGISTER_PARAMETERS(width);
}

////////////////////////////////////////////////////////////////////////////////
// Function taking options pack as parameters
////////////////////////////////////////////////////////////////////////////////
namespace window 
{ 
    template<class Options>
    void create(Options const& opt)
    {
        std::cout << "A " << opt(tag::height) << "x" << opt(tag::width)
                  << " window titled \"" << 
opt(tag::title,std::string("Untitled Window"))
                  << "\" have been created at (" 
                  << opt(tag::pos_x,0) << "," << opt(tag::pos_y,0) << ")\n";
    }
}

int main()
{
    window::create( boost::options[ tag::width = 120, tag::height = 90          
                   
                                  , tag::title = std::string("[C]hoose a File 
...")
                                  ] 
                  );

    window::create( boost::options[ tag::pos_x = 60, tag::width = 64, 
tag::height = 64] );
}
_______________________________________________
proto mailing list
proto@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/proto

Reply via email to