Boost logo

Boost-Commit :

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);
+}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk