Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get faster compilation speed with a boost.parameter like syntax?

I am currently using boost.parameter with some factory functions and compile times are getting prohibitive.

currently I have a common pattern like this:

auto thing = makeThing(property1 = foo::bar, "myThing"_thingName);

where makeThing has like 30 parameters, most of them with defaults. I would like to preserve the "named parameter like" syntax and the ability to match parameters by type not by position.

How can I get better compilation speed without changing the syntax at the call site of my factory?

note: Judging by the difference between boost.MPL speed and say brigand speed it seems to me that there should be at least an order of magnitude improvement in compile time if modern meta programming techniques were used in a boost.parameter equivalent.

update: here is a abridged example of what exactly I'm doing: in a bare metal embedded context I have different peripherals abstracted as complex templated classes following the policy based class design idiom. Each class takes a lot of configuration info at compile time and uses only the required functionality (can't rely on the optimizer to strip out unused stuff because all the SFR interactions are observable, therefore volatile so it is not allowed).

These policy based classes are super ugly for the user to configure and most embedded users run away screaming if they see a < in the public interface so I use boost.parameter to make a sexy factory to which they can pass all their type encoded wishes (like in hana style) and I generate the class as a local static hooking it up to required ISRs and passing back a handle.

namespace usb
{
    BOOST_PARAMETER_NAME(hw)
    BOOST_PARAMETER_NAME(vid)
    BOOST_PARAMETER_NAME(pid)
    BOOST_PARAMETER_NAME(device_class)
    BOOST_PARAMETER_NAME(max_packet_ep0)
    BOOST_PARAMETER_NAME(max_packet)
    BOOST_PARAMETER_NAME(packet_pool_size)
    BOOST_PARAMETER_NAME(device_description)
    BOOST_PARAMETER_NAME(device_calss_description)
    BOOST_PARAMETER_NAME(can_power_down)
    BOOST_PARAMETER_NAME(stall_supported)
    BOOST_PARAMETER_NAME(setup_packet_timeout)
    //...

BOOST_PARAMETER_FUNCTION(
    (usb_handle),
    make,    

    tag,                 

    (required(hw, *)) 

    (optional
    (vid, *, 0x6001_ci)
        (pid, *, 0x1234_ci)
        (device_class, *, cdc_class{})
        (max_packet_ep0, *, 8_ci)
        (max_packet, *, 64_ci)
        (packet_pool_size, *, 12_ci)
        (device_description, *, "")
        (device_calss_description, *, "")
        (can_power_down, *, 0_ci)
        (stall_supported, *, 0_ci)
        (setup_packet_timeout, *, 100_ci)
        )
)
{
    // makes a local static policy based class taylored at compile time 
    // to support only the specified features
    return{};  //returns a handle to the local static
}
}

Most factories have 10-25 parameters and preprocessor time seems to be the killer. It takes like 1-5 seconds per factory regardless of whether the user actually calls the function or not.

update 2: well the bounty has ended so it looks like there is no solution. If I find time I will write a boost.parameter replacement and link it here. It would also be nice to make the return type of the named parameter function depend on the input types in order to get closer to boost.hana style semantics.

like image 515
odinthenerd Avatar asked Jun 03 '16 13:06

odinthenerd


1 Answers

You can implement the via global constexpr static objects, like this:

struct init_ 
{  
    my_class operator()(int i) {return i;} 
    my_class operator= (int i) {return i;} 
};
consexpr static init_ init;

//make function
template<typename ...Args>
thingy make(Args&&...args);


auto x = make(init=42);

You might need to add an constexpr ctor to init_. You can then use boost.fusion or boost.hana to get a for_each for the sequence and initialize your type.

struct thingy { int x;};

struct x_init 
{
    int init;
    x_init (int i) : init(i) {};
    void operator()(thingy & t)
    { t.x = init;}
};

struct x_
{
    constexpr x_() {};
    x_init operator()(int i) const {return i;}
    x_init operator= (int i) const {return i;}
};
constexpr static x_ x;

template<typename ...Args>
thingy make(Args &&...)
{
     thingy t;
     auto vec = boost::fusion::make_vector(std::forward<Args>(args)...);
     boost::fusion::for_each(vec, [t](auto & init){init(t);});
}

auto t = make(x=42);

Boost.Process actually uses that, if you look into my repository on github, you find a rather complicated version of that.

like image 113
Klemens Morgenstern Avatar answered Oct 20 '22 01:10

Klemens Morgenstern