$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
From: steven_at_[hidden]
Date: 2007-08-24 13:30:18
Author: steven_watanabe
Date: 2007-08-24 13:30:18 EDT (Fri, 24 Aug 2007)
New Revision: 38910
URL: http://svn.boost.org/trac/boost/changeset/38910
Log:
Added BOOST_UNITS_DEFAULT_CONVERSION
Added:
   sandbox/units/libs/units/test/test_default_conversion.cpp   (contents, props changed)
Text files modified: 
   sandbox/units/boost/units/conversion.hpp |   310 +++++++++++++++++++++++++++++++++------ 
   sandbox/units/libs/units/test/Jamfile.v2 |    61 ++++---                                 
   2 files changed, 294 insertions(+), 77 deletions(-)
Modified: sandbox/units/boost/units/conversion.hpp
==============================================================================
--- sandbox/units/boost/units/conversion.hpp	(original)
+++ sandbox/units/boost/units/conversion.hpp	2007-08-24 13:30:18 EDT (Fri, 24 Aug 2007)
@@ -19,6 +19,7 @@
 #include <boost/mpl/divides.hpp>
 #include <boost/preprocessor/seq/enum.hpp>
 #include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/is_base_and_derived.hpp>
 
 #include <boost/units/dimension_list.hpp>
 #include <boost/units/heterogeneous_system.hpp>
@@ -66,6 +67,22 @@
 
 #endif
 
+namespace detail {
+
+template<class Source, class Dest>
+struct conversion_factor_helper;
+
+template<class Source, class Dest>
+struct call_base_unit_converter;
+
+}
+
+/// INTERNAL ONLY
+struct undefined_base_unit_converter_base {};
+
+template<class BaseUnit>
+struct get_default_conversion;
+
 /// INTERNAL ONLY
 template<class Source, class Destination>
 struct select_base_unit_converter
@@ -75,41 +92,46 @@
 };
 
 /// INTERNAL ONLY
-template<class Source, class Destination>
-struct base_unit_converter
+template<class Source, class Dest>
+struct base_unit_converter_base : undefined_base_unit_converter_base {};
+
+/// INTERNAL ONLY
+template<class Source>
+struct base_unit_converter_base<Source, BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(Source, typename Source::dimension_type)>
 {
-    typedef select_base_unit_converter<typename unscale<Source>::type, typename unscale<Destination>::type> selector;
-    typedef typename selector::source_type source_type;
-    typedef typename selector::destination_type destination_type;
-    typedef base_unit_converter<source_type, destination_type> converter;
-    typedef typename mpl::divides<typename get_scale_list<Source>::type, typename get_scale_list<source_type>::type>::type source_factor;
-    typedef typename mpl::divides<typename get_scale_list<Destination>::type, typename get_scale_list<destination_type>::type>::type destination_factor;
-    typedef typename mpl::divides<source_factor, destination_factor>::type factor;
-    typedef eval_scale_list<factor> eval_factor;
-    typedef typename multiply_typeof_helper<typename converter::type, typename eval_factor::type>::type type;
-    static type value()
-    {
-        return(converter::value() * eval_factor::value());
+    typedef one type;
+    static type value() {
+        return(one());
     }
 };
 
+/// INTERNAL ONLY
+template<class Source, class Dest>
+struct base_unit_converter : base_unit_converter_base<Source, Dest> {};
+
 namespace detail {
 
-template<bool try_inverse, bool trivial>
-struct inverse_base_unit_converter_impl;
+template<bool is_defined>
+struct do_call_base_unit_converter_impl;
 
 template<>
-struct inverse_base_unit_converter_impl<false, false>
+struct do_call_base_unit_converter_impl<true>
 {
-    template<class Source, class Destination>
-    struct apply
-    {
-        typedef select_base_unit_converter<typename unscale<Source>::type, typename unscale<typename Destination::unit_type>::type> selector;
+    template<class Source, class Dest>
+    struct apply : base_unit_converter<Source, Dest> {};
+};
+
+template<>
+struct do_call_base_unit_converter_impl<false>
+{
+    template<class Source, class Dest>
+    struct apply {
+        typedef select_base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type> selector;
         typedef typename selector::source_type source_type;
         typedef typename selector::destination_type destination_type;
         typedef base_unit_converter<source_type, destination_type> converter;
         typedef typename mpl::divides<typename get_scale_list<Source>::type, typename get_scale_list<source_type>::type>::type source_factor;
-        typedef typename mpl::divides<typename get_scale_list<Destination>::type, typename get_scale_list<destination_type>::type>::type destination_factor;
+        typedef typename mpl::divides<typename get_scale_list<Dest>::type, typename get_scale_list<destination_type>::type>::type destination_factor;
         typedef typename mpl::divides<source_factor, destination_factor>::type factor;
         typedef eval_scale_list<factor> eval_factor;
         typedef typename multiply_typeof_helper<typename converter::type, typename eval_factor::type>::type type;
@@ -120,52 +142,179 @@
     };
 };
 
+template<class Source, class Dest>
+struct do_call_base_unit_converter :
+    do_call_base_unit_converter_impl<
+        !boost::is_base_and_derived<
+            undefined_base_unit_converter_base,
+            base_unit_converter<Source, Dest>
+        >::value
+    >::template apply<Source, Dest> {};
+
+template<bool forward_is_defined, bool reverse_is_defined>
+struct call_base_unit_converter_base_unit_impl;
+
+template<>
+struct call_base_unit_converter_base_unit_impl<true, true>
+{
+    template<class Source, class Dest>
+    struct apply : do_call_base_unit_converter<Source, typename Dest::unit_type>
+    {
+    };
+};
+
+template<>
+struct call_base_unit_converter_base_unit_impl<true, false>
+{
+    template<class Source, class Dest>
+    struct apply : do_call_base_unit_converter<Source, typename Dest::unit_type>
+    {
+    };
+};
+
 template<>
-struct inverse_base_unit_converter_impl<true, false>
+struct call_base_unit_converter_base_unit_impl<false, true>
 {
-    template<class Source, class Destination>
+    template<class Source, class Dest>
     struct apply
     {
-        typedef base_unit_converter<Destination, typename Source::unit_type> inverse;
-        typedef typename inverse::type type;
-        static type value()
-        {
-            return(one()/inverse::value());
+        typedef do_call_base_unit_converter<Dest, typename Source::unit_type> converter;
+        typedef typename divide_typeof_helper<one, typename converter::type>::type type;
+        static type value() {
+            return(one() / converter::value());
         }
     };
 };
 
-template<bool dummy>
-struct inverse_base_unit_converter_impl<dummy, true>
+template<>
+struct call_base_unit_converter_base_unit_impl<false, false>
 {
-    template<class Source, class Destination>
+    template<class Source, class Dest>
     struct apply
     {
+        typedef typename get_default_conversion<Source>::type new_source;
+        typedef typename get_default_conversion<Dest>::type new_dest;
+        typedef call_base_unit_converter<Source, new_source> start;
+        typedef detail::conversion_factor_helper<
+            new_source,
+            new_dest
+        > conversion;
+        typedef call_base_unit_converter<Dest, new_dest> end;
+        typedef typename divide_typeof_helper<
+            typename multiply_typeof_helper<
+                typename start::type,
+                typename conversion::type
+            >::type,
+            typename end::type
+        >::type type;
+        static type value() {
+            return(start::value() * conversion::value() / end::value());
+        }
+    };
+};
+
+template<int N>
+struct get_default_conversion_impl
+{
+    template<class Begin>
+    struct apply
+    {
+        typedef typename mpl::deref<Begin>::type source_pair;
+        typedef typename source_pair::value_type exponent;
+        typedef typename source_pair::tag_type source;
+        typedef typename get_default_conversion<source>::type new_source;
+        typedef typename get_default_conversion_impl<N-1>::template apply<typename mpl::next<Begin>::type> next_iteration;
+        typedef typename multiply_typeof_helper<typename power_dimof_helper<new_source, exponent>::type, typename next_iteration::unit_type>::type unit_type;
+        typedef call_base_unit_converter<source, new_source> conversion;
+        typedef typename multiply_typeof_helper<typename conversion::type, typename next_iteration::type>::type type;
+        static type value() {
+            return(static_rational_power<exponent>(conversion::value()) * next_iteration::value());
+        }
+    };
+};
+
+template<>
+struct get_default_conversion_impl<0>
+{
+    template<class Begin>
+    struct apply
+    {
+        typedef unit<dimensionless_type, heterogeneous_system<heterogeneous_system_pair<dimensionless_type, dimensionless_type> > > unit_type;
         typedef one type;
-        static type value() { return(type()); }
+        static type value() {
+            return(type());
+        }
     };
 };
 
-template<class Source, class Dest>
-struct use_inverse_conversion
+template<bool is_defined>
+struct call_base_unit_converter_impl;
+
+template<>
+struct call_base_unit_converter_impl<true>
 {
-    typedef select_base_unit_converter<typename unscale<Source>::type, typename unscale<typename Dest::unit_type>::type> selector;
-    enum { value = (boost::is_same<Source, typename selector::source_type>::value) &&
-        (boost::is_same<typename Dest::unit_type, typename selector::destination_type>::value) };
+    template<class Source, class Dest>
+    struct apply : do_call_base_unit_converter<Source, Dest>
+    {
+    };
 };
 
-} // namespace detail
+template<>
+struct call_base_unit_converter_impl<false>
+{
+    template<class Source, class Dest>
+    struct apply {
+        typedef typename get_default_conversion<Source>::type new_source;
+        typedef typename Dest::system_type::type system_list;
+        typedef typename get_default_conversion_impl<mpl::size<system_list>::value>::template apply<typename mpl::begin<system_list>::type> impl;
+        typedef typename impl::unit_type new_dest;
+        typedef call_base_unit_converter<Source, new_source> start;
+        typedef conversion_factor_helper<new_source, new_dest> conversion;
+        typedef typename divide_typeof_helper<
+            typename multiply_typeof_helper<
+                typename start::type,
+                typename conversion::type
+            >::type,
+            typename impl::type
+        >::type type;
+        static type value() {
+            return(start::value() * conversion::value() / impl::value());
+        }
+    };
+};
+
+template<class Source, class Dest>
+struct base_unit_converter_scaled_is_undefined :
+    boost::is_base_and_derived<
+        undefined_base_unit_converter_base,
+        base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type>
+    > {};
+
+template<class Source, class Dest>
+struct base_unit_converter_is_undefined : 
+    mpl::and_<
+        boost::is_base_and_derived<
+            undefined_base_unit_converter_base,
+            base_unit_converter<Source, Dest>
+        >,
+        base_unit_converter_scaled_is_undefined<Source, Dest>
+    > {};
+
+template<class Source, class Dest>
+struct call_base_unit_converter : call_base_unit_converter_impl<!base_unit_converter_is_undefined<Source, Dest>::value>::template apply<Source, Dest>
+{
+};
 
-/// INTERNAL ONLY
 template<class Source, class Dest>
-struct base_unit_converter<
-    Source,
-    BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(Dest, typename Source::dimension_type)
-> : detail::inverse_base_unit_converter_impl<
-        detail::use_inverse_conversion<Source, Dest>::value,
-        boost::is_same<Source, Dest>::value
+struct call_base_unit_converter<Source, BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(Dest, typename Source::dimension_type)> :
+    call_base_unit_converter_base_unit_impl<
+        !base_unit_converter_is_undefined<Source, typename Dest::unit_type>::value,
+        !base_unit_converter_is_undefined<Dest, typename Source::unit_type>::value
     >::template apply<Source, Dest>
-{};
+{
+};
+
+} // namespace detail
 
 /// Defines the conversion factor from a base unit to any other base
 /// unit with the same dimensions.  Must appear at global scope.
@@ -259,6 +408,39 @@
 }                                                                           \
 void boost_units_require_semicolon()
 
+/// Specifies the default conversion to be applied when
+/// no direct conversion is available.
+/// Source is a base unit.  Dest is any unit with the
+/// same dimensions.
+#define BOOST_UNITS_DEFAULT_CONVERSION(Source, Dest)\
+    namespace boost {\
+    namespace units {\
+    template<>\
+    struct get_default_conversion<Source>\
+    {\
+        typedef Dest type;\
+    };\
+    }\
+    }\
+    void boost_units_require_semicolon()
+
+/// Specifies the default conversion to be applied when
+/// no direct conversion is available.
+/// Params is a PP Sequence of template arguments.
+/// Source is a base unit.  Dest is any unit with the
+/// same dimensions.
+#define BOOST_UNITS_DEFAULT_CONVERSION_TEMPLATE(Params, Source, Dest)\
+    namespace boost {\
+    namespace units {\
+    template<BOOST_PP_SEQ_ENUM(Params)>\
+    struct get_default_conversion<Source>\
+    {\
+        typedef Dest type;\
+    };\
+    }\
+    }\
+    void boost_units_require_semicolon()
+
 namespace detail {
 
 template<int N>
@@ -275,7 +457,7 @@
         typedef typename unit_pair::tag_type unit;
         typedef typename unit::dimension_type dimensions;
         typedef typename reduce_unit<units::unit<dimensions, DestinationSystem> >::type reduced_unit;
-        typedef base_unit_converter<unit, reduced_unit> converter;
+        typedef detail::call_base_unit_converter<unit, reduced_unit> converter;
         typedef typename multiply_typeof_helper<typename converter::type, typename next_iteration::type>::type type;
         static type value() { return(static_rational_power<typename unit_pair::value_type>(converter::value()) * next_iteration::value()); }
     };
@@ -441,6 +623,38 @@
     }
 };
 
+/// Requires that all possible conversions
+/// between base units are defined.
+template<class D, class S1, class S2>
+struct conversion_factor_helper<unit<D, heterogeneous_system<S1> >, unit<D, heterogeneous_system<S2> > >
+{
+    /// INTERNAL ONLY
+    typedef typename detail::extract_base_units<mpl::size<typename S1::type>::value>::template apply<
+        typename mpl::begin<typename S1::type>::type,
+        mpl::list0<>
+    >::type from_base_units;
+    /// INTERNAL ONLY
+    typedef typename detail::extract_base_units<mpl::size<typename S2::type>::value>::template apply<
+        typename mpl::begin<typename S2::type>::type,
+        from_base_units
+    >::type all_base_units;
+    /// INTERNAL ONLY
+    typedef typename detail::make_homogeneous_system<all_base_units>::type system;
+    typedef typename detail::conversion_impl<mpl::size<typename S1::type>::value>::template apply<
+        typename mpl::begin<typename S1::type>::type,
+        system
+    > conversion1;
+    typedef typename detail::conversion_impl<mpl::size<typename S2::type>::value>::template apply<
+        typename mpl::begin<typename S2::type>::type,
+        system
+    > conversion2;
+    typedef typename divide_typeof_helper<typename conversion1::type, typename conversion2::type>::type type;
+    static type value()
+    {
+        return(conversion1::value() / conversion2::value());
+    }
+};
+
 } // namespace detail
 
 /// Find the conversion factor between two units.
Modified: sandbox/units/libs/units/test/Jamfile.v2
==============================================================================
--- sandbox/units/libs/units/test/Jamfile.v2	(original)
+++ sandbox/units/libs/units/test/Jamfile.v2	2007-08-24 13:30:18 EDT (Fri, 24 Aug 2007)
@@ -7,41 +7,44 @@
 # accomanying file LICENSE_1_0.txt or copy at
 # http://www.boost.org/LICENSE_1_0.txt
 
-UNIT_REQUIREMENTS = <include>$(BOOST_ROOT) <include>../../.. <warnings>all ;
+project units_test :
+    requirements <include>$(BOOST_ROOT) <include>../../.. <warnings>all
+;
 
 import testing ;
 
 {
   test-suite units
    :
-    [ compile test_predicates.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile test_negative_denominator.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ run test_dimensionless_quantity.cpp : : : $(UNIT_REQUIREMENTS) : ]
-    [ run test_implicit_conversion.cpp : : : $(UNIT_REQUIREMENTS) : ]
-    [ run test_quantity.cpp : : : $(UNIT_REQUIREMENTS) : ]
-    [ run test_unit.cpp : : : $(UNIT_REQUIREMENTS) : ]
-    [ run test_conversion.cpp : : : $(UNIT_REQUIREMENTS) : ]
-    [ run test_base_dimension.cpp : : : $(UNIT_REQUIREMENTS) : ]
-    [ run test_absolute.cpp : : : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_implicit_conversion.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_quantity_construct.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_quantity_assign.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_quantity_add.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_quantity_subtract.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_quantity_add_assign.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_quantity_subtract_assign.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_quantity_scalar_add.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_quantity_scalar_subtract.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_quantity_unit_add.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_quantity_unit_subtract.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_scalar_quantity_add.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_scalar_quantity_subtract.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_unit_quantity_add.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_unit_quantity_subtract.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_adl_detail.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_heterogeneous_unit.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_base_dimension.cpp : $(UNIT_REQUIREMENTS) : ]
-    [ compile-fail fail_add_temperature.cpp : $(UNIT_REQUIREMENTS) : ]
+    [ compile test_predicates.cpp : : ]
+    [ compile test_negative_denominator.cpp : : ]
+    [ run test_dimensionless_quantity.cpp : : : : ]
+    [ run test_implicit_conversion.cpp : : : : ]
+    [ run test_quantity.cpp : : : : ]
+    [ run test_unit.cpp : : : : ]
+    [ run test_conversion.cpp : : : : ]
+    [ run test_base_dimension.cpp : : : : ]
+    [ run test_absolute.cpp : : : : ]
+    [ run test_default_conversion.cpp : : : : ]
+    [ compile-fail fail_implicit_conversion.cpp : : ]
+    [ compile-fail fail_quantity_construct.cpp : : ]
+    [ compile-fail fail_quantity_assign.cpp : : ]
+    [ compile-fail fail_quantity_add.cpp : : ]
+    [ compile-fail fail_quantity_subtract.cpp : : ]
+    [ compile-fail fail_quantity_add_assign.cpp : : ]
+    [ compile-fail fail_quantity_subtract_assign.cpp : : ]
+    [ compile-fail fail_quantity_scalar_add.cpp : : ]
+    [ compile-fail fail_quantity_scalar_subtract.cpp : : ]
+    [ compile-fail fail_quantity_unit_add.cpp : : ]
+    [ compile-fail fail_quantity_unit_subtract.cpp : : ]
+    [ compile-fail fail_scalar_quantity_add.cpp : : ]
+    [ compile-fail fail_scalar_quantity_subtract.cpp : : ]
+    [ compile-fail fail_unit_quantity_add.cpp : : ]
+    [ compile-fail fail_unit_quantity_subtract.cpp : : ]
+    [ compile-fail fail_adl_detail.cpp : : ]
+    [ compile-fail fail_heterogeneous_unit.cpp : : ]
+    [ compile-fail fail_base_dimension.cpp : : ]
+    [ compile-fail fail_add_temperature.cpp : : ]
    ;
 
 }
Added: sandbox/units/libs/units/test/test_default_conversion.cpp
==============================================================================
--- (empty file)
+++ sandbox/units/libs/units/test/test_default_conversion.cpp	2007-08-24 13:30:18 EDT (Fri, 24 Aug 2007)
@@ -0,0 +1,40 @@
+// mcs::units - A C++ library for zero-overhead dimensional analysis and 
+// unit/quantity manipulation and conversion
+//
+// Copyright (C) 2003-2007 Matthias Christian Schabel
+// Copyright (C) 2007 Steven Watanabe
+//
+// Distributed under 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/test/minimal.hpp>
+
+#include <boost/units/base_dimension.hpp>
+#include <boost/units/base_unit.hpp>
+#include <boost/units/conversion.hpp>
+#include <boost/units/unit.hpp>
+
+struct dimension_tag : boost::units::base_dimension<dimension_tag, 1> {};
+
+typedef dimension_tag::dimension_type dimension;
+
+struct unit1_tag : boost::units::base_unit<unit1_tag, dimension, 1> {}; 
+
+struct unit2_tag : boost::units::base_unit<unit2_tag, dimension, 2> {};
+
+struct unit3_tag : boost::units::base_unit<unit3_tag, dimension, 3> {};
+
+BOOST_UNITS_DEFINE_BASE_CONVERSION(unit1_tag, unit2_tag, double, 2.0);
+
+BOOST_UNITS_DEFINE_BASE_CONVERSION(unit2_tag, unit3_tag, double, 3.0);
+
+BOOST_UNITS_DEFAULT_CONVERSION(unit1_tag, unit2_tag::unit_type);
+
+BOOST_UNITS_DEFAULT_CONVERSION(unit3_tag, unit2_tag::unit_type);
+
+int test_main(int, char*[]) {
+    double value = boost::units::conversion_factor(unit3_tag::unit_type(), unit1_tag::unit_type());
+    BOOST_CHECK(std::abs(value - 1.0/6.0) < .0000000001);
+    return(0);
+}