/** * @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" namespace LLUnits { template struct HighestPrecisionType { typedef T type_t; }; template<> struct HighestPrecisionType { typedef F64 type_t; }; template<> struct HighestPrecisionType { typedef S64 type_t; }; template<> struct HighestPrecisionType { typedef S64 type_t; }; template<> struct HighestPrecisionType { typedef S64 type_t; }; template<> struct HighestPrecisionType { typedef S64 type_t; }; template<> struct HighestPrecisionType { typedef S64 type_t; }; template<> struct HighestPrecisionType { typedef S64 type_t; }; template struct ConversionFactor { static typename HighestPrecisionType::type_t get() { // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template llstatic_assert(sizeof(DERIVED_UNITS_TAG) == 0, "Cannot convert between types."); } }; template struct ConversionFactor { static typename HighestPrecisionType::type_t get() { return 1; } }; } template struct LLUnit { typedef LLUnit self_t; typedef STORAGE_TYPE storage_t; // value initialization LLUnit(storage_t value = storage_t()) : mValue(value) {} // unit initialization and conversion template LLUnit(LLUnit other) : mValue(convert(other)) {} // value assignment self_t& operator = (storage_t value) { mValue = value; return *this; } // unit assignment template self_t& operator = (LLUnit other) { mValue = convert(other); return *this; } storage_t value() const { return mValue; } template LLUnit as() { return LLUnit(*this); } void operator += (storage_t value) { mValue += value; } template void operator += (LLUnit other) { mValue += convert(other); } void operator -= (storage_t value) { mValue -= value; } template void operator -= (LLUnit other) { mValue -= convert(other); } void operator *= (storage_t multiplicand) { mValue *= multiplicand; } template void operator *= (LLUnit multiplicand) { // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template llstatic_assert(sizeof(OTHER_UNIT) == 0, "Multiplication of unit types not supported."); } void operator /= (storage_t divisor) { mValue /= divisor; } template void operator /= (LLUnit divisor) { // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template llstatic_assert(sizeof(OTHER_UNIT) == 0, "Illegal in-place division of unit types."); } template static storage_t convert(LLUnit v) { return (storage_t)(v.value() * LLUnits::ConversionFactor::get() * LLUnits::ConversionFactor::get()); } protected: storage_t mValue; }; template struct LLUnitImplicit : public LLUnit { typedef LLUnitImplicit self_t; typedef typename LLUnit::storage_t storage_t; typedef LLUnit base_t; LLUnitImplicit(storage_t value = storage_t()) : base_t(value) {} template LLUnitImplicit(LLUnit 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 value(); } }; // // operator + // template LLUnit operator + (LLUnit first, LLUnit second) { LLUnit result(first); result += second; return result; } template LLUnit operator + (LLUnit first, SCALAR_TYPE second) { LLUnit result(first); result += second; return result; } template LLUnit operator + (SCALAR_TYPE first, LLUnit second) { LLUnit result(first); result += second; return result; } template LLUnitImplicit operator + (LLUnitImplicit first, LLUnit second) { LLUnitImplicit result(first); result += second; return result; } template LLUnitImplicit operator + (LLUnitImplicit first, SCALAR_TYPE second) { LLUnitImplicit result(first); result += second; return result; } template LLUnitImplicit operator + (LLUnitImplicit first, LLUnitImplicit second) { LLUnitImplicit result(first); result += second; return result; } // // operator - // template LLUnit operator - (LLUnit first, LLUnit second) { LLUnit result(first); result -= second; return result; } template LLUnit operator - (LLUnit first, SCALAR_TYPE second) { LLUnit result(first); result -= second; return result; } template LLUnit operator - (SCALAR_TYPE first, LLUnit second) { LLUnit result(first); result -= second; return result; } template LLUnitImplicit operator - (LLUnitImplicit first, LLUnitImplicit second) { LLUnitImplicit result(first); result -= second; return result; } template LLUnitImplicit operator - (LLUnitImplicit first, SCALAR_TYPE second) { LLUnitImplicit result(first); result -= second; return result; } template LLUnitImplicit operator - (SCALAR_TYPE first, LLUnitImplicit second) { LLUnitImplicit result(first); result -= second; return result; } // // operator * // template LLUnit operator * (SCALAR_TYPE first, LLUnit second) { return LLUnit(first * second.value()); } template LLUnit operator * (LLUnit first, SCALAR_TYPE second) { return LLUnit(first.value() * second); } template LLUnit operator * (LLUnit, LLUnit) { // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template llstatic_assert(sizeof(STORAGE_TYPE1) == 0, "Multiplication of unit types results in new unit type - not supported."); return LLUnit(); } template LLUnitImplicit operator * (SCALAR_TYPE first, LLUnitImplicit second) { return LLUnitImplicit(first * second.value()); } template LLUnitImplicit operator * (LLUnitImplicit first, SCALAR_TYPE second) { return LLUnitImplicit(first.value() * second); } template LLUnitImplicit operator * (LLUnitImplicit, LLUnitImplicit) { // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template llstatic_assert(sizeof(STORAGE_TYPE1) == 0, "Multiplication of unit types results in new unit type - not supported."); return LLUnitImplicit(); } // // operator / // template SCALAR_TYPE operator / (SCALAR_TYPE first, LLUnit second) { return SCALAR_TYPE(first / second.value()); } template LLUnit operator / (LLUnit first, SCALAR_TYPE second) { return LLUnit(first.value() / second); } template STORAGE_TYPE1 operator / (LLUnit first, LLUnit 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 LLUnitImplicit operator / (LLUnitImplicit first, SCALAR_TYPE second) { return LLUnitImplicit(first.value() / second); } template STORAGE_TYPE1 operator / (LLUnitImplicit first, LLUnitImplicit 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 \ bool operator op (SCALAR_TYPE first, LLUnit second) \ { \ return first op second.value(); \ } \ \ template \ bool operator op (LLUnit first, SCALAR_TYPE second) \ { \ return first.value() op second; \ } \ \ template \ bool operator op (LLUnitImplicit first, LLUnitImplicit second) \ { \ return first.value() op first.convert(second); \ } \ \ template \ bool operator op (LLUnit first, LLUnit second) \ { \ return first.value() op first.convert(second); \ } COMPARISON_OPERATORS(<) COMPARISON_OPERATORS(<=) COMPARISON_OPERATORS(>) COMPARISON_OPERATORS(>=) COMPARISON_OPERATORS(==) COMPARISON_OPERATORS(!=) namespace LLUnits { template T rawValue(T val) { return val; } template STORAGE_TYPE rawValue(LLUnit val) { return val.value(); } template STORAGE_TYPE rawValue(LLUnitImplicit val) { return val.value(); } template struct HighestPrecisionType > { typedef typename HighestPrecisionType::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 \ struct ConversionFactor \ { \ static typename HighestPrecisionType::type_t get() \ { \ return typename HighestPrecisionType::type_t(conversion_factor); \ } \ }; \ \ template \ struct ConversionFactor \ { \ static typename HighestPrecisionType::type_t get() \ { \ return typename HighestPrecisionType::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