1 // Boost.Units - A C++ library for zero-overhead dimensional analysis and 2 // unit/quantity manipulation and conversion 3 // 4 // Copyright (C) 2003-2008 Matthias Christian Schabel 5 // Copyright (C) 2008 Steven Watanabe 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See 8 // accompanying file LICENSE_1_0.txt or copy at 9 // http://www.boost.org/LICENSE_1_0.txt) 10 11 #ifndef BOOST_UNITS_DETAIL_HETEROGENEOUS_CONVERSION_HPP 12 #define BOOST_UNITS_DETAIL_HETEROGENEOUS_CONVERSION_HPP 13 14 #include <boost/mpl/minus.hpp> 15 #include <boost/mpl/times.hpp> 16 17 #include <boost/units/static_rational.hpp> 18 #include <boost/units/homogeneous_system.hpp> 19 #include <boost/units/detail/linear_algebra.hpp> 20 21 namespace boost { 22 23 namespace units { 24 25 namespace detail { 26 27 struct solve_end { 28 template<class Begin, class Y> 29 struct apply { 30 typedef dimensionless_type type; 31 }; 32 }; 33 34 struct no_solution {}; 35 36 template<class X1, class X2, class Next> 37 struct solve_normal { 38 template<class Begin, class Y> 39 struct apply { 40 typedef typename Begin::next next; 41 typedef list< 42 typename mpl::minus< 43 typename mpl::times<X1, Y>::type, 44 typename mpl::times<X2, typename Begin::item>::type 45 >::type, 46 typename Next::template apply<next, Y>::type 47 > type; 48 }; 49 }; 50 51 template<class Next> 52 struct solve_leading_zeroes { 53 template<class Begin> 54 struct apply { 55 typedef list< 56 typename Begin::item, 57 typename Next::template apply<typename Begin::next>::type 58 > type; 59 }; 60 typedef solve_leading_zeroes type; 61 }; 62 63 template<> 64 struct solve_leading_zeroes<no_solution> { 65 typedef no_solution type; 66 }; 67 68 template<class Next> 69 struct solve_first_non_zero { 70 template<class Begin> 71 struct apply { 72 typedef typename Next::template apply< 73 typename Begin::next, 74 typename Begin::item 75 >::type type; 76 }; 77 }; 78 79 template<class Next> 80 struct solve_internal_zero { 81 template<class Begin, class Y> 82 struct apply { 83 typedef list< 84 typename Begin::item, 85 typename Next::template apply<typename Begin::next, Y>::type 86 > type; 87 }; 88 }; 89 90 template<class T> 91 struct make_solve_list_internal_zero { 92 template<class Next, class X> 93 struct apply { 94 typedef solve_normal<T, X, Next> type; 95 }; 96 }; 97 98 template<> 99 struct make_solve_list_internal_zero<static_rational<0> > { 100 template<class Next, class X> 101 struct apply { 102 typedef solve_internal_zero<Next> type; 103 }; 104 }; 105 106 template<int N> 107 struct make_solve_list_normal { 108 template<class Begin, class X> 109 struct apply { 110 typedef typename make_solve_list_internal_zero< 111 typename Begin::item 112 >::template apply< 113 typename make_solve_list_normal<N-1>::template apply<typename Begin::next, X>::type, 114 X 115 >::type type; 116 }; 117 }; 118 119 template<> 120 struct make_solve_list_normal<0> { 121 template<class Begin, class X> 122 struct apply { 123 typedef solve_end type; 124 }; 125 }; 126 127 template<int N> 128 struct make_solve_list_leading_zeroes; 129 130 template<class T> 131 struct make_solve_list_first_non_zero { 132 template<class Begin, int N> 133 struct apply { 134 typedef solve_first_non_zero< 135 typename make_solve_list_normal<N-1>::template apply< 136 typename Begin::next, 137 typename Begin::item 138 >::type 139 > type; 140 }; 141 }; 142 143 template<> 144 struct make_solve_list_first_non_zero<static_rational<0> > { 145 template<class Begin, int N> 146 struct apply { 147 typedef typename solve_leading_zeroes< 148 typename make_solve_list_leading_zeroes<N-1>::template apply< 149 typename Begin::next 150 >::type 151 >::type type; 152 }; 153 }; 154 155 template<int N> 156 struct make_solve_list_leading_zeroes { 157 template<class Begin> 158 struct apply { 159 typedef typename make_solve_list_first_non_zero<typename Begin::item>::template apply<Begin, N>::type type; 160 }; 161 }; 162 163 template<> 164 struct make_solve_list_leading_zeroes<0> { 165 template<class Begin> 166 struct apply { 167 typedef no_solution type; 168 }; 169 }; 170 171 template<int N> 172 struct try_add_unit_impl { 173 template<class Begin, class L> 174 struct apply { 175 typedef typename try_add_unit_impl<N-1>::template apply<typename Begin::next, L>::type next; 176 typedef typename Begin::item::template apply<next>::type type; 177 BOOST_STATIC_ASSERT((next::size::value - 1 == type::size::value)); 178 }; 179 }; 180 181 template<> 182 struct try_add_unit_impl<0> { 183 template<class Begin, class L> 184 struct apply { 185 typedef L type; 186 }; 187 }; 188 189 template<int N> 190 struct make_homogeneous_system_impl; 191 192 template<class T, bool is_done> 193 struct make_homogeneous_system_func; 194 195 template<class T> 196 struct make_homogeneous_system_func<T, false> { 197 template<class Begin, class Current, class Units, class Dimensions, int N> 198 struct apply { 199 typedef typename make_homogeneous_system_impl<N-1>::template apply< 200 typename Begin::next, 201 list<T, Current>, 202 list<typename Begin::item, Units>, 203 Dimensions 204 >::type type; 205 }; 206 }; 207 208 template<class T> 209 struct make_homogeneous_system_func<T, true> { 210 template<class Begin, class Current, class Units, class Dimensions, int N> 211 struct apply { 212 typedef list<typename Begin::item, Units> type; 213 }; 214 }; 215 216 template<> 217 struct make_homogeneous_system_func<no_solution, false> { 218 template<class Begin, class Current, class Units, class Dimensions, int N> 219 struct apply { 220 typedef typename make_homogeneous_system_impl<N-1>::template apply< 221 typename Begin::next, 222 Current, 223 Units, 224 Dimensions 225 >::type type; 226 }; 227 }; 228 229 template<> 230 struct make_homogeneous_system_func<no_solution, true> { 231 template<class Begin, class Current, class Units, class Dimensions, int N> 232 struct apply { 233 typedef typename make_homogeneous_system_impl<N-1>::template apply< 234 typename Begin::next, 235 Current, 236 Units, 237 Dimensions 238 >::type type; 239 }; 240 }; 241 242 template<int N> 243 struct make_homogeneous_system_impl { 244 template<class Begin, class Current, class Units, class Dimensions> 245 struct apply { 246 typedef typename expand_dimensions<Dimensions::size::value>::template apply< 247 Dimensions, 248 typename Begin::item::dimension_type 249 >::type dimensions; 250 typedef typename try_add_unit_impl<Current::size::value>::template apply<Current, dimensions>::type new_element; 251 typedef typename make_solve_list_leading_zeroes<new_element::size::value>::template apply<new_element>::type new_func; 252 typedef typename make_homogeneous_system_func< 253 new_func, 254 ((Current::size::value)+1) == (Dimensions::size::value) 255 >::template apply<Begin, Current, Units, Dimensions, N>::type type; 256 }; 257 }; 258 259 template<> 260 struct make_homogeneous_system_impl<0> { 261 template<class Begin, class Current, class Units, class Dimensions> 262 struct apply { 263 typedef Units type; 264 }; 265 }; 266 267 template<class Units> 268 struct make_homogeneous_system { 269 typedef typename find_base_dimensions<Units>::type base_dimensions; 270 typedef homogeneous_system< 271 typename insertion_sort< 272 typename make_homogeneous_system_impl< 273 Units::size::value 274 >::template apply< 275 Units, 276 dimensionless_type, 277 dimensionless_type, 278 base_dimensions 279 >::type 280 >::type 281 > type; 282 }; 283 284 template<int N> 285 struct extract_base_units { 286 template<class Begin, class T> 287 struct apply { 288 typedef list< 289 typename Begin::item::tag_type, 290 typename extract_base_units<N-1>::template apply<typename Begin::next, T>::type 291 > type; 292 }; 293 }; 294 295 template<> 296 struct extract_base_units<0> { 297 template<class Begin, class T> 298 struct apply { 299 typedef T type; 300 }; 301 }; 302 303 } 304 305 } 306 307 } 308 309 #endif 310