|
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