diff options
Diffstat (limited to 'indra/llcommon/llunit.h')
-rw-r--r-- | indra/llcommon/llunit.h | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h new file mode 100644 index 0000000000..f86f111b90 --- /dev/null +++ b/indra/llcommon/llunit.h @@ -0,0 +1,476 @@ +/** + * @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_LLUNIT_H +#define LL_LLUNIT_H + +#include "stdtypes.h" +#include "llpreprocessor.h" +#include "llerrorlegacy.h" + +namespace LLUnits +{ + +template<typename T> +struct HighestPrecisionType +{ + typedef T type_t; +}; + +template<> struct HighestPrecisionType<F32> { typedef F64 type_t; }; +template<> struct HighestPrecisionType<S32> { typedef S64 type_t; }; +template<> struct HighestPrecisionType<U32> { typedef S64 type_t; }; +template<> struct HighestPrecisionType<S16> { typedef S64 type_t; }; +template<> struct HighestPrecisionType<U16> { typedef S64 type_t; }; +template<> struct HighestPrecisionType<S8> { typedef S64 type_t; }; +template<> struct HighestPrecisionType<U8> { typedef S64 type_t; }; + +template<typename DERIVED_UNITS_TAG, typename BASE_UNITS_TAG, typename VALUE_TYPE> +struct ConversionFactor +{ + static typename HighestPrecisionType<VALUE_TYPE>::type_t get() + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + llstatic_assert_template(DERIVED_UNITS_TAG, false, "Cannot convert between types."); + } +}; + +template<typename BASE_UNITS_TAG, typename VALUE_TYPE> +struct ConversionFactor<BASE_UNITS_TAG, BASE_UNITS_TAG, VALUE_TYPE> +{ + static typename HighestPrecisionType<VALUE_TYPE>::type_t get() + { + return 1; + } +}; + +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE> +struct LLUnit +{ + typedef LLUnit<UNIT_TYPE, STORAGE_TYPE> self_t; + typedef STORAGE_TYPE storage_t; + + // value initialization + LLUnit(storage_t value = storage_t()) + : mValue(value) + {} + + // unit initialization and conversion + template<typename OTHER_UNIT, typename OTHER_STORAGE> + LLUnit(LLUnit<OTHER_UNIT, OTHER_STORAGE> other) + : mValue(convert(other)) + {} + + // value assignment + self_t& operator = (storage_t value) + { + mValue = value; + return *this; + } + + // unit assignment + template<typename OTHER_UNIT, typename OTHER_STORAGE> + self_t& operator = (LLUnit<OTHER_UNIT, OTHER_STORAGE> other) + { + mValue = convert(other); + return *this; + } + + storage_t value() const + { + return mValue; + } + + template<typename NEW_UNIT_TYPE> LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE> as() + { + return LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE>(*this); + } + + + void operator += (storage_t value) + { + mValue += value; + } + + template<typename OTHER_UNIT, typename OTHER_STORAGE> + void operator += (LLUnit<OTHER_UNIT, OTHER_STORAGE> other) + { + mValue += convert(other); + } + + void operator -= (storage_t value) + { + mValue -= value; + } + + template<typename OTHER_UNIT, typename OTHER_STORAGE> + void operator -= (LLUnit<OTHER_UNIT, OTHER_STORAGE> other) + { + mValue -= convert(other); + } + + void operator *= (storage_t multiplicand) + { + mValue *= multiplicand; + } + + template<typename OTHER_UNIT, typename OTHER_STORAGE> + void operator *= (LLUnit<OTHER_UNIT, OTHER_STORAGE> multiplicand) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + llstatic_assert_template(OTHER_UNIT, false, "Multiplication of unit types not supported."); + } + + void operator /= (storage_t divisor) + { + mValue /= divisor; + } + + template<typename OTHER_UNIT, typename OTHER_STORAGE> + void operator /= (LLUnit<OTHER_UNIT, OTHER_STORAGE> divisor) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + llstatic_assert_template(OTHER_UNIT, false, "Illegal in-place division of unit types."); + } + + template<typename SOURCE_UNITS, typename SOURCE_STORAGE> + static storage_t convert(LLUnit<SOURCE_UNITS, SOURCE_STORAGE> v) + { + return (storage_t)(v.value() + * LLUnits::ConversionFactor<SOURCE_UNITS, typename UNIT_TYPE::base_unit_t, SOURCE_STORAGE>::get() + * LLUnits::ConversionFactor<typename UNIT_TYPE::base_unit_t, UNIT_TYPE, STORAGE_TYPE>::get()); + } + +protected: + storage_t mValue; +}; + +template<typename UNIT_TYPE, typename STORAGE_TYPE> +struct LLUnitImplicit : public LLUnit<UNIT_TYPE, STORAGE_TYPE> +{ + typedef LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> self_t; + typedef typename LLUnit<UNIT_TYPE, STORAGE_TYPE>::storage_t storage_t; + typedef LLUnit<UNIT_TYPE, STORAGE_TYPE> base_t; + + LLUnitImplicit(storage_t value = storage_t()) + : base_t(value) + {} + + template<typename OTHER_UNIT, typename OTHER_STORAGE> + LLUnitImplicit(LLUnit<OTHER_UNIT, OTHER_STORAGE> other) + : base_t(convert(other)) + {} + + // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD scalar (F32, S32, etc) + // this allows for interoperability with legacy code + operator storage_t() const + { + return base_t::value(); + } +}; + +// +// operator + +// +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> +LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second) +{ + LLUnit<UNIT_TYPE1, STORAGE_TYPE1> result(first); + result += second; + return result; +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnit<UNIT_TYPE, STORAGE_TYPE> operator + (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) +{ + LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first); + result += second; + return result; +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnit<UNIT_TYPE, STORAGE_TYPE> operator + (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second) +{ + LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first); + result += second; + return result; +} + +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> +LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second) +{ + LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first); + result += second; + return result; +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator + (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) +{ + LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first); + result += second; + return result; +} + +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> +LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second) +{ + LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first); + result += second; + return result; +} + +// +// operator - +// +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> +LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator - (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second) +{ + LLUnit<UNIT_TYPE1, STORAGE_TYPE1> result(first); + result -= second; + return result; +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnit<UNIT_TYPE, STORAGE_TYPE> operator - (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) +{ + LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first); + result -= second; + return result; +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnit<UNIT_TYPE, STORAGE_TYPE> operator - (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second) +{ + LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first); + result -= second; + return result; +} + +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> +LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator - (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second) +{ + LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first); + result -= second; + return result; +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator - (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) +{ + LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first); + result -= second; + return result; +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator - (SCALAR_TYPE first, LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> second) +{ + LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first); + result -= second; + return result; +} + +// +// operator * +// +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnit<UNIT_TYPE, STORAGE_TYPE> operator * (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second) +{ + return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first * second.value())); +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnit<UNIT_TYPE, STORAGE_TYPE> operator * (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) +{ + return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() * second)); +} + +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> +LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator * (LLUnit<UNIT_TYPE1, STORAGE_TYPE1>, LLUnit<UNIT_TYPE2, STORAGE_TYPE2>) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + llstatic_assert_template(STORAGE_TYPE1, false, "Multiplication of unit types results in new unit type - not supported."); + return LLUnit<UNIT_TYPE1, STORAGE_TYPE1>(); +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator * (SCALAR_TYPE first, LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> second) +{ + return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first * second.value()); +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator * (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) +{ + return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first.value() * second); +} + +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> +LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator * (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1>, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2>) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + llstatic_assert_template(STORAGE_TYPE1, false, "Multiplication of unit types results in new unit type - not supported."); + return LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1>(); +} + +// +// operator / +// +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +SCALAR_TYPE operator / (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second) +{ + return SCALAR_TYPE(first / second.value()); +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnit<UNIT_TYPE, STORAGE_TYPE> operator / (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) +{ + return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() / second)); +} + +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> +STORAGE_TYPE1 operator / (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + return STORAGE_TYPE1(first.value() / second.value()); +} + +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator / (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) +{ + return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() / second)); +} + +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> +STORAGE_TYPE1 operator / (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + return STORAGE_TYPE1(first.value() / second.value()); +} + +#define COMPARISON_OPERATORS(op) \ +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> \ +bool operator op (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second) \ +{ \ + return first op second.value(); \ +} \ + \ +template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> \ +bool operator op (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) \ +{ \ + return first.value() op second; \ +} \ + \ +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> \ +bool operator op (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second) \ +{ \ + return first.value() op first.convert(second); \ +} \ + \ +template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> \ + bool operator op (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second) \ +{ \ + return first.value() op first.convert(second); \ +} + +COMPARISON_OPERATORS(<) +COMPARISON_OPERATORS(<=) +COMPARISON_OPERATORS(>) +COMPARISON_OPERATORS(>=) +COMPARISON_OPERATORS(==) +COMPARISON_OPERATORS(!=) + +namespace LLUnits +{ +template<typename T> +T rawValue(T val) { return val; } + +template<typename UNIT_TYPE, typename STORAGE_TYPE> +STORAGE_TYPE rawValue(LLUnit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); } + +template<typename UNIT_TYPE, typename STORAGE_TYPE> +STORAGE_TYPE rawValue(LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); } + +template<typename UNIT_TYPE, typename STORAGE_TYPE> +struct HighestPrecisionType<LLUnit<UNIT_TYPE, STORAGE_TYPE> > +{ + typedef typename HighestPrecisionType<STORAGE_TYPE>::type_t type_t; +}; + +#define LL_DECLARE_DERIVED_UNIT(conversion_factor, base_unit_name, unit_name) \ +struct unit_name \ +{ \ + typedef base_unit_name base_unit_t; \ +}; \ +template<typename STORAGE_TYPE> \ +struct ConversionFactor<unit_name, base_unit_name, STORAGE_TYPE> \ +{ \ + static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() \ + { \ + return typename HighestPrecisionType<STORAGE_TYPE>::type_t(conversion_factor); \ + } \ +}; \ + \ +template<typename STORAGE_TYPE> \ +struct ConversionFactor<base_unit_name, unit_name, STORAGE_TYPE> \ +{ \ + static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() \ + { \ + return typename HighestPrecisionType<STORAGE_TYPE>::type_t(1.0 / (conversion_factor)); \ + } \ +} + +struct Bytes { typedef Bytes base_unit_t; }; +LL_DECLARE_DERIVED_UNIT(1024, Bytes, Kilobytes); +LL_DECLARE_DERIVED_UNIT(1024 * 1024, Bytes, Megabytes); +LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024, Bytes, Gigabytes); +LL_DECLARE_DERIVED_UNIT(1.0 / 8.0, Bytes, Bits); +LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Kilobits); +LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Megabits); +LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024 / 8, Bytes, Gigabits); + +struct Seconds { typedef Seconds base_unit_t; }; +LL_DECLARE_DERIVED_UNIT(60, Seconds, Minutes); +LL_DECLARE_DERIVED_UNIT(60 * 60, Seconds, Hours); +LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Seconds, Milliseconds); +LL_DECLARE_DERIVED_UNIT(1.0 / 1000000.0, Seconds, Microseconds); +LL_DECLARE_DERIVED_UNIT(1.0 / 1000000000.0, Seconds, Nanoseconds); + +struct Meters { typedef Meters base_unit_t; }; +LL_DECLARE_DERIVED_UNIT(1000, Meters, Kilometers); +LL_DECLARE_DERIVED_UNIT(1.0 / 100.0, Meters, Centimeters); +LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Meters, Millimeters); + +struct Hertz { typedef Hertz base_unit_t; }; +LL_DECLARE_DERIVED_UNIT(1000, Hertz, Kilohertz); +LL_DECLARE_DERIVED_UNIT(1000 * 1000, Hertz, Megahertz); +LL_DECLARE_DERIVED_UNIT(1000 * 1000 * 1000, Hertz, Gigahertz); +} // namespace LLUnits + +#endif // LL_LLUNIT_H |