Boost logo

Boost :

From: Daniel Wallin (dalwan01_at_[hidden])
Date: 2004-01-13 00:51:49


Matthias Schabel wrote:
> Sorry...the whole library also has an unfortunate tendency to send
> compilers to the graveyard...

I had a bit of free time (or rather, this was more fun than the things I
am supposed to do); here's a prototype which uses mpl::set<> like
techniques, probably works on gcc only without some additional work.
Hope this can help to give some ideas on how compile times can be
decreased.

-- 
Daniel Wallin

// Copyright Daniel Wallin 2004. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/mpl/int.hpp>
#include <boost/mpl/iterator_tag.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/clear.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/copy_if.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/minus.hpp>
#include <boost/mpl/negate.hpp>
#include <boost/mpl/apply_if.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/fold.hpp>

namespace mpl = boost::mpl;

struct dimension_tag;

struct nil_dimension
{
    nil_dimension() {}

    typedef mpl::int_<0> list_size;
    typedef dimension_tag tag;
};

template<
    class Tag
  , class Exp
  , class Next = nil_dimension
>
struct dimension;

template<class T>
char get_exponent2(...);

template<class T, class E, class N>
typename dimension<T, E, N>::size_type get_exponent2(dimension<T, E, N>*);

template<
    class Tag
  , class Exp
  , class Next
>
struct dimension : Next
{
    typedef dimension_tag tag;
    typedef Next next;
    typedef dimension type;
    typedef Exp exponent;
    typedef Tag tag_type;

    typedef typename Next::list_size::next list_size;

    BOOST_STATIC_CONSTANT(int,
        size_value = (
            Exp::value < 0 ? 32768 + Exp::value : Exp::value
        )
    );

    dimension() {}

    template<class T>
    dimension(T const& x)
        : Next(x)
    {
        BOOST_STATIC_ASSERT((
                sizeof(get_exponent2<Tag>((T*)0)) == size_value + 1
        ));
    }

    typedef char (&size_type)[size_value + 1];
};

template<class Dimension>
struct dimension_iterator
{
    typedef mpl::forward_iterator_tag category;

    typedef dimension_iterator<
        typename Dimension::next
> next;

    typedef Dimension type;
};

template<>
struct dimension_iterator<nil_dimension>
{
    typedef mpl::forward_iterator_tag category;
};

namespace boost {
namespace mpl {

template<>
struct begin_traits<dimension_tag>
{
    template<typename Dimensions> struct algorithm
    {
        typedef dimension_iterator<Dimensions> type;
    };
};

template<>
struct end_traits<dimension_tag>
{
    template<typename> struct algorithm
    {
        typedef dimension_iterator<nil_dimension> type;
    };
};

template<>
struct push_front_traits<dimension_tag>
{
    template<typename Dimensions, class T>
    struct algorithm
    {
        typedef dimension<typename T::tag_type, typename T::exponent, Dimensions> type;
    };
};

template<>
struct clear_traits<dimension_tag>
{
    template<typename> struct algorithm
    {
        typedef nil_dimension type;
    };
};

}} // namespace boost::mpl

#include <iostream>
#include <typeinfo>

template<class Dimensions, class Tag>
struct exponent
{
    BOOST_STATIC_CONSTANT(int,
        size_val = (
            sizeof(get_exponent2<Tag>((Dimensions*)0)) - 1
        )
    );

    typedef mpl::int_<
        (size_val > 16384 ? size_val - 32768 : size_val)
> type;

    BOOST_STATIC_CONSTANT(int,
        value = type::value
    );
};

template<class A, class B>
struct mul_result
{
    struct push_front_calc
    {
        template<class L, class T>
        struct apply
        {
            typedef typename mpl::plus<
                typename T::exponent
              , exponent<B, typename T::tag_type>
>::type new_exponent;

            typedef typename mpl::apply_if<
                mpl::equal_to<new_exponent, mpl::int_<0> >
              , mpl::identity<L>
              , mpl::push_front<
                    L
                  , dimension<
                        typename T::tag_type
                      , new_exponent
>
>
>::type type;
        };
    };

    typedef typename mpl::fold<
          A
        , nil_dimension
        , push_front_calc
>::type type_;

    struct not_in_A
    {
        template<class T>
        struct apply
        {
            typedef mpl::bool_<
                sizeof(get_exponent2<typename T::tag_type>((A*)0)) == 1
> type;
        };
    };
    
    typedef typename mpl::copy_if<
        B
      , type_
      , mpl::push_front<mpl::_, mpl::_>
      , not_in_A
>::type type;
};

template<class A, class B>
struct div_result
{
    struct push_front_calc
    {
        template<class L, class T>
        struct apply
        {
            typedef typename mpl::minus<
                typename T::exponent
              , exponent<B, typename T::tag_type>
>::type new_exponent;

            typedef typename mpl::apply_if<
                mpl::equal_to<new_exponent, mpl::int_<0> >
              , mpl::identity<L>
              , mpl::push_front<
                    L
                  , dimension<
                        typename T::tag_type
                      , new_exponent
>
>
>::type type;
        };
    };

    typedef typename mpl::fold<
          A
        , nil_dimension
        , push_front_calc
>::type type_;

    struct not_in_A
    {
        template<class T>
        struct apply
            : mpl::bool_<
                sizeof(get_exponent2<typename T::tag_type>((A*)0)) == 1
>
        {};
    };
    
    struct push_negated
    {
        template<class Dimensions, class T>
        struct apply
        {
            typedef dimension<
                typename T::tag_type
                , typename mpl::negate<typename T::exponent>::type
> type_;

            typedef typename mpl::push_front<Dimensions, type_>::type type;
        };
    };
 
    typedef typename mpl::copy_if<
        B
      , type_
      , push_negated
      , not_in_A
>::type type;
};

// -------------------------------------------------------------------

template<bool B> struct enable_if_same_size_impl
{
    typedef void* type;
};

template<> struct enable_if_same_size_impl<false> {};

template<class A, class B>
struct enable_if_same_size
    : enable_if_same_size_impl<
          A::list_size::value
       == B::list_size::value
>
{};

template<class Dimensions>
struct value : Dimensions
{
    value() {}

    template<class U>
    value(value<U> const& v, typename enable_if_same_size<Dimensions, U>::type = 0)
        : Dimensions(v.base())
        , val(v.val)
    {
    }

    value(double v) : val(v) {}

    Dimensions const& base() const
    {
        return *this;
    }

    double val;
};

template<class A, class B>
value<typename mul_result<A, B>::type> operator*(value<A> const& a, value<B> const& b)
{
    return value<typename mul_result<A, B>::type>(a.val * b.val);
}

template<class A, class B>
value<typename div_result<A, B>::type> operator/(value<A> const& a, value<B> const& b)
{
    return value<typename div_result<A, B>::type>(a.val / b.val);
}

template<class A, class B>
value<A> operator+(value<A> const& a, value<B> const& b)
{
    value<A> x(b);
    return value<A>(a.val + b.val);
}

template<class A, class B>
value<A> operator-(value<A> const& a, value<B> const& b)
{
    value<A> x(b);
    return value<A>(a.val - b.val);
}

template<class Dimensions>
void output_dimension(std::ostream& o, Dimensions*)
{
    o << " " << typename Dimensions::tag_type();

    if (Dimensions::exponent::value != 1)
        o << "^" << Dimensions::exponent::value;

    output_dimension(o, (typename Dimensions::next*)0);
}

void output_dimension(std::ostream& o, nil_dimension*) {}

template<class Dimensions>
std::ostream& operator<<(std::ostream& o, value<Dimensions> const& x)
{
    o << x.val;

    output_dimension(o, (Dimensions*)0);

    return o;
}

// ------------------------------------------------------------------

struct meters_ {};
struct seconds_ {};

std::ostream& operator<<(std::ostream& o, meters_)
{
    std::cout << "m";
}

std::ostream& operator<<(std::ostream& o, seconds_)
{
    std::cout << "s";
}

typedef value<
    dimension<
        meters_
      , mpl::int_<1>
      , dimension<
            seconds_
          , mpl::int_<-1>
>
>
> velocity;

typedef value<
    dimension<
        meters_
      , mpl::int_<1>
      , dimension<
            seconds_
          , mpl::int_<-2>
>
>
> acceleration;

typedef value<
    dimension<
        meters_
      , mpl::int_<1>
>
> meters;

typedef value<
    dimension<
        seconds_
      , mpl::int_<1>
>
> seconds;

int main()
{
    meters m(10.f);
    seconds t(3.f);

    velocity s = m / t;
    acceleration a = s / t + m / (t * t);
    a = (s / t) + a;

    std::cout << m * m * (m + m) * t << "\n";
    std::cout << meters(10) / (seconds(3) * seconds(3)) << "\n";
}


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