// // quantity.hpp // // Copyright (c) 2001 by Michael S. Kenniston. The most recent // version will be available at www.boost.org. Permission is granted // to use this code without restriction so long as this copyright // notice appears in all source files. // This code is provided as-is, with no warrantee of correctness. #ifndef _BFAFCE65_5FA7_11d5_B9D8_000000000000 #define _BFAFCE65_5FA7_11d5_B9D8_000000000000 // for MSVC, 4248 is invalid access to "private" - must be treated as an error // for MSVC, 4786 is truncated names in debugger - ignore #pragma warning( error:4248; disable:4786 ) #include namespace quantities { typedef double Rep; template< int D1, int D2, int D3, int D4 = 0, int D5 = 0, int D6 = 0, int D7 = 0 > struct dimensions { enum { dim1 = D1, dim2 = D2, dim3 = D3, dim4 = D4, dim5 = D5, dim6 = D6, dim7 = D7 }; }; template< typename Dims > class quantity; namespace detail { inline void show_dim( std::ostream & os, const char * label, int exp ) { if( exp == 0 ) return; os << " " << label; if( exp > 1 ) os << "+"; if( exp != 1 ) os << exp; } template< typename Dims > struct select { typedef quantity< Dims > type; }; template<> struct select< dimensions< 0, 0, 0 > > { typedef Rep type; }; template< typename LeftDims, typename RightDims > struct product { enum { d1 = LeftDims::dim1 + RightDims::dim1, d2 = LeftDims::dim2 + RightDims::dim2, d3 = LeftDims::dim3 + RightDims::dim3, d4 = LeftDims::dim4 + RightDims::dim4, d5 = LeftDims::dim5 + RightDims::dim5, d6 = LeftDims::dim6 + RightDims::dim6, d7 = LeftDims::dim7 + RightDims::dim7 }; typedef select< dimensions< d1, d2, d3, d4, d5, d6, d7 > >::type type; }; template< typename LeftDims, typename RightDims > struct quotient { enum { d1 = LeftDims::dim1 - RightDims::dim1, d2 = LeftDims::dim2 - RightDims::dim2, d3 = LeftDims::dim3 - RightDims::dim3, d4 = LeftDims::dim4 - RightDims::dim4, d5 = LeftDims::dim5 - RightDims::dim5, d6 = LeftDims::dim6 - RightDims::dim6, d7 = LeftDims::dim7 - RightDims::dim7 }; typedef select< dimensions< d1, d2, d3, d4, d5, d6, d7 > >::type type; }; template< typename Dims > struct inverse { enum { d1 = - Dims::dim1, d2 = - Dims::dim2, d3 = - Dims::dim3, d4 = - Dims::dim4, d5 = - Dims::dim5, d6 = - Dims::dim6, d7 = - Dims::dim7 }; typedef select< dimensions< d1, d2, d3, d4, d5, d6, d7 > >::type type; }; struct wrap { Rep value; explicit wrap( Rep v ) : value( v ) {} operator Rep() { return value; } }; } // namespace detail struct zero_t { operator float() { return 0.0; } }; zero_t zero() { zero_t z; return z; } template< typename Dims > class quantity { public: quantity() {} // default copy constructor is ok quantity( const zero_t & ) : value( 0.0 ) {} // default assignment operator is ok quantity & operator=( const zero_t & ) { value = 0.0; return *this; } // default destructor is ok quantity & operator+=( const quantity & rhs ) { value += rhs.value; return *this; } quantity & operator-=( const quantity & rhs ) { value -= rhs.value; return *this; } quantity & operator*=( Rep rhs ) { value *= rhs; return *this; } quantity & operator/=( Rep rhs ) { value /= rhs; return *this; } quantity operator+() const { return quantity( +value ); } quantity operator-() const { return quantity( -value ); } quantity operator+( quantity rhs ) const { return quantity( value + rhs.value ); } quantity operator-( quantity rhs ) const { return quantity( value - rhs.value ); } quantity operator*( Rep rhs ) const { return quantity( value * rhs ); } quantity operator/( Rep rhs ) const { return quantity( value / rhs ); } template< typename RightDims > typename detail::product< Dims, RightDims >::type operator*( const quantity< RightDims > & rhs ) const { return detail::product< Dims, RightDims >::type ( detail::wrap( value * rhs.get( detail::wrap( 0 ) ) ) ); } template< typename RightDims > typename detail::quotient< Dims, RightDims >::type operator/( const quantity< RightDims > & rhs ) const { return detail::quotient< Dims, RightDims >::type ( detail::wrap( value / rhs.get( detail::wrap( 0 ) ) ) ); } detail::inverse< Dims >::type inv_div( Rep lhs ) const { return detail::inverse< Dims >::type( detail::wrap( lhs / value ) ); } bool operator==( const quantity & rhs ) const { return value == rhs.value; } bool operator!=( const quantity & rhs ) const { return value != rhs.value; } bool operator> ( const quantity & rhs ) const { return value > rhs.value; } bool operator>=( const quantity & rhs ) const { return value >= rhs.value; } bool operator< ( const quantity & rhs ) const { return value < rhs.value; } bool operator<=( const quantity & rhs ) const { return value <= rhs.value; } explicit quantity( const detail::wrap & w ) : value( w.value ) {} Rep get( const detail::wrap & ) const { return value; } std::ostream & print( std::ostream & ) const; private: quantity( Rep val ): value( val ) {} Rep value; }; template< typename RightDims > inline quantity< RightDims > operator*( Rep lhs, const quantity< RightDims > & rhs ) { return rhs * lhs; } template< typename RightDims > inline detail::inverse< RightDims >::type operator/( Rep lhs, const quantity< RightDims > & rhs ) { return rhs.inv_div( lhs ); } template< typename Dims > inline std::ostream & quantity< Dims >::print( std::ostream & os ) const { os << value; detail::show_dim( os, "m", Dims::dim1 ); detail::show_dim( os, "kg", Dims::dim2 ); detail::show_dim( os, "s", Dims::dim3 ); detail::show_dim( os, "A", Dims::dim4 ); detail::show_dim( os, "K", Dims::dim5 ); detail::show_dim( os, "mol", Dims::dim6 ); detail::show_dim( os, "cd", Dims::dim7 ); return os; } template< typename Dims > inline std::ostream & operator<<( std::ostream & os, const quantity< Dims > & rhs ) { return rhs.print( os ); } typedef dimensions< 1, 0, 0, 0, 0, 0, 0 > length_d; typedef dimensions< 0, 1, 0, 0, 0, 0, 0 > mass_d; typedef dimensions< 0, 0, 1, 0, 0, 0, 0 > time_interval_d; typedef dimensions< 0, 0, 0, 1, 0, 0, 0 > electric_current_d; typedef dimensions< 0, 0, 0, 0, 1, 0, 0 > thermodynamic_temperature_d; typedef dimensions< 0, 0, 0, 0, 0, 1, 0 > amount_of_substance_d; typedef dimensions< 0, 0, 0, 0, 0, 0, 1 > luminous_intensity_d; namespace detail { struct base_units { static quantity< length_d > meter() { return quantity< length_d > ( wrap( 1.0 ) ); } static quantity< mass_d > kilogram() { return quantity< mass_d > ( wrap( 1.0 ) ); } static quantity< time_interval_d > second() { return quantity< time_interval_d > ( wrap( 1.0 ) ); } static quantity< electric_current_d > ampere() { return quantity< electric_current_d > ( wrap( 1.0 ) ); } static quantity< thermodynamic_temperature_d > kelvin() { return quantity< thermodynamic_temperature_d >( wrap( 1.0 ) ); } static quantity< amount_of_substance_d > mole() { return quantity< amount_of_substance_d > ( wrap( 1.0 ) ); } static quantity< luminous_intensity_d > candela() { return quantity< luminous_intensity_d > ( wrap( 1.0 ) ); } }; } // namespace detail inline quantity< length_d > meter() { return detail::base_units::meter(); } inline quantity< mass_d > kilogram() { return detail::base_units::kilogram(); } inline quantity< time_interval_d > second() { return detail::base_units::second(); } inline quantity< electric_current_d > ampere() { return detail::base_units::ampere(); } inline quantity< thermodynamic_temperature_d >kelvin() { return detail::base_units::kelvin(); } inline quantity< amount_of_substance_d > mole() { return detail::base_units::mole(); } inline quantity< luminous_intensity_d > candela() { return detail::base_units::candela(); } } // namespace quantities #endif // _BFAFCE65_5FA7_11d5_B9D8_000000000000