diff options
author | Richard Linden <none@none> | 2013-08-27 13:41:19 -0700 |
---|---|---|
committer | Richard Linden <none@none> | 2013-08-27 13:41:19 -0700 |
commit | a7aed07a5b620977fb74e4070e432eef01d11d3c (patch) | |
tree | fad55eec609b298b066384e91ccf6425af8a53af /indra/llcommon/llunittype.h | |
parent | 7ab616c18786afcb40ab0092fe6f8c6a3a799375 (diff) |
broke out llunit.h into llunittype.h and llunits.h for unit declarations
changed unit declarations macros to make a lot more sense
Diffstat (limited to 'indra/llcommon/llunittype.h')
-rw-r--r-- | indra/llcommon/llunittype.h | 734 |
1 files changed, 734 insertions, 0 deletions
diff --git a/indra/llcommon/llunittype.h b/indra/llcommon/llunittype.h new file mode 100644 index 0000000000..949e4492c7 --- /dev/null +++ b/indra/llcommon/llunittype.h @@ -0,0 +1,734 @@ +/** + * @file llunit.h + * @brief Unit conversion classes + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_UNITTYPE_H +#define LL_UNITTYPE_H + +#include "stdtypes.h" +#include "llpreprocessor.h" +#include "llerror.h" + +//lightweight replacement of type traits for simple type equality check +template<typename S, typename T> +struct LLIsSameType +{ + static const bool value = false; +}; + +template<typename T> +struct LLIsSameType<T, T> +{ + static const bool value = true; +}; + +// workaround for decltype() not existing and typeof() not working inline in gcc 4.2 +template<typename S, typename T> +struct LLResultTypeAdd +{ + typedef LL_TYPEOF(S() + T()) type_t; +}; + +template<typename S, typename T> +struct LLResultTypeSubtract +{ + typedef LL_TYPEOF(S() - T()) type_t; +}; + +template<typename S, typename T> +struct LLResultTypeMultiply +{ + typedef LL_TYPEOF(S() * T()) type_t; +}; + +template<typename S, typename T> +struct LLResultTypeDivide +{ + typedef LL_TYPEOF(S() / T(1)) type_t; +}; + +template<typename S, typename T> +struct LLResultTypePromote +{ + typedef LL_TYPEOF((true) ? S() : T()) type_t; +}; + +template<typename STORAGE_TYPE, typename UNIT_TYPE> +struct LLUnit +{ + typedef LLUnit<STORAGE_TYPE, UNIT_TYPE> self_t; + typedef STORAGE_TYPE storage_t; + + // value initialization + LL_FORCE_INLINE explicit LLUnit(storage_t value = storage_t()) + : mValue(value) + {} + + // unit initialization and conversion + template<typename OTHER_STORAGE, typename OTHER_UNIT> + LL_FORCE_INLINE LLUnit(LLUnit<OTHER_STORAGE, OTHER_UNIT> other) + : mValue(convert(other).mValue) + {} + + storage_t value() const + { + return mValue; + } + + void value(storage_t value) + { + mValue = value; + } + + template<typename NEW_UNIT_TYPE> + storage_t valueInUnits() + { + return LLUnit<storage_t, NEW_UNIT_TYPE>(*this).value(); + } + + template<typename NEW_UNIT_TYPE> + void valueInUnits(storage_t value) + { + *this = LLUnit<storage_t, NEW_UNIT_TYPE>(value); + } + + void operator += (self_t other) + { + mValue += convert(other).mValue; + } + + void operator -= (self_t other) + { + mValue -= convert(other).mValue; + } + + void operator *= (storage_t multiplicand) + { + mValue *= multiplicand; + } + + void operator *= (self_t multiplicand) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported."); + } + + void operator /= (storage_t divisor) + { + mValue /= divisor; + } + + void operator /= (self_t divisor) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types."); + } + + template<typename SOURCE_STORAGE, typename SOURCE_UNITS> + LL_FORCE_INLINE static self_t convert(LLUnit<SOURCE_STORAGE, SOURCE_UNITS> v) + { + typedef typename LLResultTypePromote<STORAGE_TYPE, SOURCE_STORAGE>::type_t result_storage_t; + LLUnit<result_storage_t, UNIT_TYPE> result; + result_storage_t divisor = ll_convert_units(v, result); + result.value(result.value() / divisor); + return self_t(result.value()); + } + +protected: + storage_t mValue; +}; + +template<typename STORAGE_TYPE, typename UNIT_TYPE> +std::ostream& operator <<(std::ostream& s, const LLUnit<STORAGE_TYPE, UNIT_TYPE>& unit) +{ + s << unit.value() << UNIT_TYPE::getUnitLabel(); + return s; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE> +std::istream& operator >>(std::istream& s, LLUnit<STORAGE_TYPE, UNIT_TYPE>& unit) +{ + STORAGE_TYPE val; + s >> val; + unit.value(val); + return s; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE> +struct LLUnitImplicit : public LLUnit<STORAGE_TYPE, UNIT_TYPE> +{ + typedef LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> self_t; + typedef typename LLUnit<STORAGE_TYPE, UNIT_TYPE>::storage_t storage_t; + typedef LLUnit<STORAGE_TYPE, UNIT_TYPE> base_t; + + LLUnitImplicit(storage_t value = storage_t()) + : base_t(value) + {} + + template<typename OTHER_STORAGE, typename OTHER_UNIT> + LLUnitImplicit(LLUnit<OTHER_STORAGE, OTHER_UNIT> other) + : base_t(other) + {} + + // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD value (F32, S32, etc) + // this allows for interoperability with legacy code + operator storage_t() const + { + return base_t::value(); + } + + using base_t::operator +=; + void operator += (storage_t value) + { + base_t::mValue += value; + } + + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template<typename OTHER_STORAGE, typename OTHER_UNIT> + void operator += (LLUnitImplicit<OTHER_STORAGE, OTHER_UNIT> other) + { + base_t::mValue += convert(other).value(); + } + + using base_t::operator -=; + void operator -= (storage_t value) + { + base_t::mValue -= value; + } + + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template<typename OTHER_STORAGE, typename OTHER_UNIT> + void operator -= (LLUnitImplicit<OTHER_STORAGE, OTHER_UNIT> other) + { + base_t::mValue -= convert(other).value(); + } + +}; + +template<typename STORAGE_TYPE, typename UNIT_TYPE> +std::ostream& operator <<(std::ostream& s, const LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE>& unit) +{ + s << unit.value() << UNIT_TYPE::getUnitLabel(); + return s; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE> +std::istream& operator >>(std::istream& s, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE>& unit) +{ + STORAGE_TYPE val; + s >> val; + unit = val; + return s; +} + +template<typename S1, typename T1, typename S2, typename T2> +LL_FORCE_INLINE S2 ll_convert_units(LLUnit<S1, T1> in, LLUnit<S2, T2>& out) +{ + S2 divisor(1); + + LL_STATIC_ASSERT((LLIsSameType<T1, T2>::value + || !LLIsSameType<T1, typename T1::base_unit_t>::value + || !LLIsSameType<T2, typename T2::base_unit_t>::value), + "conversion requires compatible units"); + + if (LLIsSameType<T1, T2>::value) + { + // T1 and T2 same type, just assign + out.value((S2)in.value()); + } + else if (T1::sLevel > T2::sLevel) + { + // reduce T1 + LLUnit<S2, typename T1::base_unit_t> new_in; + divisor *= (S2)ll_convert_units(in, new_in); + divisor *= (S2)ll_convert_units(new_in, out); + } + else + { + // reduce T2 + LLUnit<S2, typename T2::base_unit_t> new_out; + divisor *= (S2)ll_convert_units(in, new_out); + divisor *= (S2)ll_convert_units(new_out, out); + } + return divisor; +} + +template<typename T> +struct LLStorageType +{ + typedef T type_t; +}; + +template<typename STORAGE_TYPE, typename UNIT_TYPE> +struct LLStorageType<LLUnit<STORAGE_TYPE, UNIT_TYPE> > +{ + typedef STORAGE_TYPE type_t; +}; + +// all of these operators need to perform type promotion on the storage type of the units, so they +// cannot be expressed as operations on identical types with implicit unit conversion +// e.g. typeof(S32Bytes(x) + F32Megabytes(y)) <==> F32Bytes + +// +// operator + +// +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> operator + (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator + (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, UNITLESS second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNIT_TYPE>(0); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator + (UNITLESS first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNIT_TYPE>(0); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> operator + (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> result(first); + result += LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1>(second); + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> +LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE> operator + (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, UNITLESS_TYPE second) +{ + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> +LLUnitImplicit<typename LLResultTypeAdd<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>:: + type_t, UNIT_TYPE> operator + (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> second) +{ + LLUnitImplicit<typename LLResultTypeAdd<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> result(first); + result += second; + return result; +} + +// +// operator - +// +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> operator - (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator - (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, UNITLESS second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNIT_TYPE>(0); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator - (UNITLESS first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNIT_TYPE>(0); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> operator - (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> operator - (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> operator - (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNIT_TYPE1> result(first); + result -= LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1>(second); + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> +LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE> operator - (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, UNITLESS_TYPE second) +{ + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> +LLUnitImplicit<typename LLResultTypeSubtract<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator - (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> second) +{ + LLUnitImplicit<typename LLResultTypeSubtract<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> result(first); + result -= second; + return result; +} + +// +// operator * +// +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnit<STORAGE_TYPE1, UNIT_TYPE1> operator * (LLUnit<STORAGE_TYPE1, UNIT_TYPE1>, LLUnit<STORAGE_TYPE2, UNIT_TYPE2>) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnit<STORAGE_TYPE1, UNIT_TYPE1>(); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> +LLUnit<typename LLResultTypeMultiply<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE> operator * (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, UNITLESS_TYPE second) +{ + return LLUnit<typename LLResultTypeMultiply<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE>(first.value() * second); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> +LLUnit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator * (UNITLESS_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second) +{ + return LLUnit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE>(first * second.value()); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator * (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1>, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2>) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1>(); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> +LLUnitImplicit<typename LLResultTypeMultiply<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE> operator * (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, UNITLESS_TYPE second) +{ + return LLUnitImplicit<typename LLResultTypeMultiply<STORAGE_TYPE, UNITLESS_TYPE>::type_t, UNIT_TYPE>(first.value() * second); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> +LLUnitImplicit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator * (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> second) +{ + return LLUnitImplicit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE>(first * second.value()); +} + + +// +// operator / +// + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> +LLUnit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE> operator / (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, UNITLESS_TYPE second) +{ + return LLUnit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE>(first.value() / second); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + return first.value() / first.convert(second).value(); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> +LLUnitImplicit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE> operator / (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, UNITLESS_TYPE second) +{ + return LLUnitImplicit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNIT_TYPE>(first.value() / second); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); +} + +// +// comparison operators +// + +#define LL_UNIT_DECLARE_COMPARISON_OPERATOR(op) \ +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> \ +bool operator op (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} \ + \ +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> \ +bool operator op (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, UNITLESS_TYPE second) \ +{ \ + return first.value() op second; \ +} \ + \ +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> \ +bool operator op (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> second) \ +{ \ + return first op second.value(); \ +} \ + \ +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> \ +bool operator op (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} \ + \ +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> \ +bool operator op (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, UNITLESS_TYPE second) \ +{ \ + LL_BAD_TEMPLATE_INSTANTIATION(UNITLESS_TYPE, "operator " #op " requires compatible unit types"); \ + return false; \ +} \ + \ +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename UNITLESS_TYPE> \ +bool operator op (UNITLESS_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second) \ +{ \ + LL_BAD_TEMPLATE_INSTANTIATION(UNITLESS_TYPE, "operator " #op " requires compatible unit types"); \ + return false; \ +} \ + \ +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> \ +bool operator op (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} \ + \ +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> \ +bool operator op (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} + +LL_UNIT_DECLARE_COMPARISON_OPERATOR(<); +LL_UNIT_DECLARE_COMPARISON_OPERATOR(<=); +LL_UNIT_DECLARE_COMPARISON_OPERATOR(>); +LL_UNIT_DECLARE_COMPARISON_OPERATOR(>=); +LL_UNIT_DECLARE_COMPARISON_OPERATOR(==); +LL_UNIT_DECLARE_COMPARISON_OPERATOR(!=); + + +template<typename T> +struct LLGetUnitLabel +{ + static const char* getUnitLabel() { return ""; } +}; + +template<typename T, typename STORAGE_T> +struct LLGetUnitLabel<LLUnit<STORAGE_T, T> > +{ + static const char* getUnitLabel() { return T::getUnitLabel(); } +}; + +template<typename T> +struct LLUnitLinearOps +{ + typedef LLUnitLinearOps<T> self_t; + + LLUnitLinearOps(T val) + : mValue(val), + mDivisor(1) + {} + + template<typename OTHER_T> + self_t operator * (OTHER_T other) + { + return mValue * other; + } + + template<typename OTHER_T> + self_t operator / (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template<typename OTHER_T> + self_t operator + (OTHER_T other) + { + mValue /= mDivisor; + mValue += other; + return *this; + } + + template<typename OTHER_T> + self_t operator - (OTHER_T other) + { + mValue /= mDivisor; + mValue -= other; + return *this; + } + + T mValue; + T mDivisor; +}; + +template<typename T> +struct LLUnitInverseLinearOps +{ + typedef LLUnitInverseLinearOps<T> self_t; + + LLUnitInverseLinearOps(T val) + : mValue(val), + mDivisor(1) + {} + + template<typename OTHER_T> + self_t operator * (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template<typename OTHER_T> + self_t operator / (OTHER_T other) + { + mValue *= other; + return *this; + } + + template<typename OTHER_T> + self_t operator + (OTHER_T other) + { + mValue /= mDivisor; + mValue -= other; + return *this; + } + + template<typename OTHER_T> + self_t operator - (OTHER_T other) + { + mValue /= mDivisor; + mValue += other; + return *this; + } + + T mValue; + T mDivisor; +}; + +#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ +struct base_unit_name \ +{ \ + static const int sLevel = 0; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template<typename T> \ + static LLUnit<T, base_unit_name> fromValue(T value) { return LLUnit<T, base_unit_name>(value); } \ + template<typename STORAGE_T, typename UNIT_T> \ + static LLUnit<STORAGE_T, base_unit_name> fromValue(LLUnit<STORAGE_T, UNIT_T> value) \ + { return LLUnit<STORAGE_T, base_unit_name>(value); } \ +} + + +#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \ +struct unit_name \ +{ \ + static const int sLevel = base_unit_name::sLevel + 1; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template<typename T> \ + static LLUnit<T, unit_name> fromValue(T value) { return LLUnit<T, unit_name>(value); } \ + template<typename STORAGE_T, typename UNIT_T> \ + static LLUnit<STORAGE_T, unit_name> fromValue(LLUnit<STORAGE_T, UNIT_T> value) \ + { return LLUnit<STORAGE_T, unit_name>(value); } \ +}; \ + \ +template<typename S1, typename S2> \ +LL_FORCE_INLINE S2 ll_convert_units(LLUnit<S1, unit_name> in, LLUnit<S2, base_unit_name>& out) \ +{ \ + typedef typename LLResultTypePromote<S1, S2>::type_t result_storage_t; \ + LLUnitInverseLinearOps<result_storage_t> op = \ + LLUnitInverseLinearOps<result_storage_t>(in.value()) conversion_operation; \ + out = LLUnit<S2, base_unit_name>((S2)op.mValue); \ + return op.mDivisor; \ +} \ + \ +template<typename S1, typename S2> \ +LL_FORCE_INLINE S2 ll_convert_units(LLUnit<S1, base_unit_name> in, LLUnit<S2, unit_name>& out) \ +{ \ + typedef typename LLResultTypePromote<S1, S2>::type_t result_storage_t; \ + LLUnitLinearOps<result_storage_t> op = \ + LLUnitLinearOps<result_storage_t>(in.value()) conversion_operation; \ + out = LLUnit<S2, unit_name>((S2)op.mValue); \ + return op.mDivisor; \ +} + +#define LL_DECLARE_UNIT_TYPEDEFS(ns, unit_name) \ + typedef LLUnit<F32, ns::unit_name> F32##unit_name; \ + typedef LLUnitImplicit<F32, ns::unit_name> F32##unit_name##Implicit;\ + typedef LLUnit<F64, ns::unit_name> F64##unit_name; \ + typedef LLUnitImplicit<F64, ns::unit_name> F64##unit_name##Implicit;\ + typedef LLUnit<S32, ns::unit_name> S32##unit_name; \ + typedef LLUnitImplicit<S32, ns::unit_name> S32##unit_name##Implicit;\ + typedef LLUnit<S64, ns::unit_name> S64##unit_name; \ + typedef LLUnitImplicit<S64, ns::unit_name> S64##unit_name##Implicit;\ + typedef LLUnit<U32, ns::unit_name> U32##unit_name; \ + typedef LLUnitImplicit<U32, ns::unit_name> U32##unit_name##Implicit;\ + typedef LLUnit<U64, ns::unit_name> U64##unit_name; \ + typedef LLUnitImplicit<U64, ns::unit_name> U64##unit_name##Implicit + +#endif //LL_UNITTYPE_H |