Boost logo

Boost :

From: Phil Richards (news_at_[hidden])
Date: 2004-01-17 14:31:15


On Sat, 17 Jan 2004 15:58:28 +0000, Phil Richards wrote:
[With respect to my physical quantities/units library]
> I have made a start (and some significant progress) on
> porting over to a boost::mpl implementation. Although I got something
> that basically works as the current form (side note: factor of 2-3 fold
> slow down on compilation times), I'm having a play with the MPL to see if
> I can remove even more of the "hard-coded" sizing. (All that is left are
> the conversion and printing routines.)

Well, I've finished the cut over to boost::mpl::vector.
I now have something that is functionally equivalent (well, pretty much),
has the possibility for extensionality being done fairly cleanly now - SI
is defined as:

struct si
{
    typedef boost::mpl::vector7<u::kilogram, u::meter, u::second,
                                u::ampere, u::kelvin, u::candela,
                                u::mole> units_type;
};

(It is trivial, therefore, to define new unit systems. I'm in the middle
of a secondary cut-over for how things like "second" are defined.)

BUT, and this is a big but, the compilation times are appalling. They
have surpassed Matthias' :-) From the 3 seconds that I had with a fixed
vector, I hit about 6 seconds just by doing the main calculations with MPL
stuff. When I cut-over the unit conversion code to a rather tidy
compile-time fold-based approach, it the time increased to a little over
10 seconds.

The killer has been cutting over the output routines to a fold-based
approach - just doing this has increased compilation times to 150 seconds.

Ouch.

Are there any obvious things I should be looking at? Especially with
respect to things like using mpl::fold, mpl::zip_view, mpl::vector - I
don't use much more than those.
(Compiler is gcc 3.3.2.)

There are things I can do to step-back from the pure-MPL approach I'm
taking, but the solution I've got reminds me of my functional programming
days and gives me a warm fuzzy feeling.

phil

Here's the code (fragment) in question (probably won't compile 'cos
of how I've cut and pasted it). The idea was to take a vector of
rational's (with members numerator and denominator), zip it with
the units vector from the unit system (see "si" above), and then fold
it with an operator that outputs each term in sequence. The BMV
template argument is (currently) a boost::mpl::vector7.

struct output_fold_base {
    static bool do_print(std::ostream &a_out) {
        return false;
    }
};
 
struct output_fold_op {
    template<typename ResultSoFar, typename Value>
    struct apply {
        struct type {
            static bool do_print(std::ostream &a_out);
        };
    };
};
 
template<typename ResultSoFar, typename Value>
bool
output_fold_op::apply<ResultSoFar, Value>::type::do_print(std::ostream &a_out)
{
    const bool outputAlreadyDone = ResultSoFar::do_print(a_out);
 
    using namespace boost::mpl;
 
    typedef typename at_c<Value, 0>::type Power;
    if (Power::numerator == 0) return outputAlreadyDone;
    if (outputAlreadyDone) a_out << '.';
 
    a_out << at_c<Value, 1>::type::abbreviation();
    if (Power::numerator != 1 || Power::denominator != 1) {
        a_out << '^';
        if (Power::denominator == 1)
            a_out << Power::numerator;
        else
            a_out << '(' << Power::numerator
                << '/' << Power::denominator << ')';
    }
 
    return true;
}

template<typename Dimensionality, typename UnitSystem>
struct output_helper;
 
template<typename BMV, typename UnitSystem>
struct output_helper<dimensional<BMV>, UnitSystem> {
    static void do_print(std::ostream &a_out);
};
 
template<typename BMV, typename UnitSystem> void
output_helper<dimensional<BMV>, UnitSystem>::do_print(std::ostream &a_out)
{
    using namespace boost::mpl;
    fold<
        zip_view<
            vector2<
                BMV,
                typename UnitSystem::units_type
>
>,
        output_fold_base,
        output_fold_op
>::type::do_print(a_out);
}

template<typename ValueType, typename Dimensionality, typename UnitSystem>
std::ostream& operator<<(std::ostream &a_out,
    const quantity<ValueType, Dimensionality, UnitSystem> &a_quantity)
{
    a_out << a_quantity.get();
    output_helper<Dimensionality, UnitSystem>::do_print(a_out); return
    a_out;
}

-- 
change name before "@" to "phil" for email

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk