/** * @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" #include 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).mValue) {} bool operator == (const self_t& other) { return mValue = other.mValue; } // value assignment self_t& operator = (storage_t value) { mValue = value; return *this; } // unit assignment template self_t& operator = (LLUnit other) { mValue = convert(other).mValue; return *this; } storage_t value() const { return mValue; } template STORAGE_TYPE getAs() { return LLUnit(*this).value(); } template STORAGE_TYPE setAs(STORAGE_TYPE val) { *this = LLUnit(val); } void operator += (storage_t value) { mValue += value; } template void operator += (LLUnit other) { mValue += convert(other).mValue; } void operator -= (storage_t value) { mValue -= value; } template void operator -= (LLUnit other) { mValue -= convert(other).mValue; } 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 LL_BAD_TEMPLATE_INSTANTIATION(OTHER_UNIT, "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 LL_BAD_TEMPLATE_INSTANTIATION(OTHER_UNIT, "Illegal in-place division of unit types."); } template static self_t convert(LLUnit v) { self_t result; ll_convert_units(v, result); return result; } 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 base_t::value(); } }; template LL_FORCE_INLINE void ll_convert_units(LLUnit in, LLUnit& out, ...) { typedef boost::integral_constant::value || !boost::is_same::value || !boost::is_same::value> conversion_valid_t; LL_STATIC_ASSERT(conversion_valid_t::value, "invalid conversion"); if (boost::is_same::value) { if (boost::is_same::value) { // T1 and T2 fully reduced and equal...just copy out = (S2)in.value(); } else { // reduce T2 LLUnit new_out; ll_convert_units(in, new_out); ll_convert_units(new_out, out); } } else { // reduce T1 LLUnit new_in; ll_convert_units(in, new_in); ll_convert_units(new_in, out); } } // // 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((STORAGE_TYPE)(first * second.value())); } template LLUnit operator * (LLUnit first, SCALAR_TYPE second) { return LLUnit((STORAGE_TYPE)(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 LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "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 LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "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((STORAGE_TYPE)(first.value() / second)); } template STORAGE_TYPE1 operator / (LLUnit first, LLUnit second) { return STORAGE_TYPE1(first.value() / first.convert(second)); } template LLUnitImplicit operator / (LLUnitImplicit first, SCALAR_TYPE second) { return LLUnitImplicit((STORAGE_TYPE)(first.value() / second)); } template STORAGE_TYPE1 operator / (LLUnitImplicit first, LLUnitImplicit second) { return STORAGE_TYPE1(first.value() / first.convert(second)); } #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(!=) template struct LLGetUnitLabel { static const char* getUnitLabel() { return ""; } }; template struct LLGetUnitLabel > { static const char* getUnitLabel() { return T::getUnitLabel(); } }; template struct LLUnitLinearOps { typedef LLUnitLinearOps self_t; LLUnitLinearOps(VALUE_TYPE val) : mValue (val) {} operator VALUE_TYPE() const { return mValue; } VALUE_TYPE mValue; template self_t operator * (T other) { return mValue * other; } template self_t operator / (T other) { return mValue / other; } template self_t operator + (T other) { return mValue + other; } template self_t operator - (T other) { return mValue - other; } }; template struct LLUnitInverseLinearOps { typedef LLUnitInverseLinearOps self_t; LLUnitInverseLinearOps(VALUE_TYPE val) : mValue (val) {} operator VALUE_TYPE() const { return mValue; } VALUE_TYPE mValue; template self_t operator * (T other) { return mValue / other; } template self_t operator / (T other) { return mValue * other; } template self_t operator + (T other) { return mValue - other; } template self_t operator - (T other) { return mValue + other; } }; #define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ struct base_unit_name { typedef base_unit_name base_unit_t; static const char* getUnitLabel() { return unit_label; }} #define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \ struct unit_name \ { \ typedef base_unit_name base_unit_t; \ static const char* getUnitLabel() { return unit_label; } \ }; \ \ template \ void ll_convert_units(LLUnit in, LLUnit& out) \ { \ out = (S2)(LLUnitLinearOps(in.value()) conversion_operation).mValue; \ } \ \ template \ void ll_convert_units(LLUnit in, LLUnit& out) \ { \ out = (S2)(LLUnitInverseLinearOps(in.value()) conversion_operation).mValue; \ } // // Unit declarations // namespace LLUnits { LL_DECLARE_BASE_UNIT(Bytes, "B"); LL_DECLARE_DERIVED_UNIT(Kilobytes, "KB", Bytes, * 1000); LL_DECLARE_DERIVED_UNIT(Megabytes, "MB", Kilobytes, * 1000); LL_DECLARE_DERIVED_UNIT(Gigabytes, "GB", Megabytes, * 1000); LL_DECLARE_DERIVED_UNIT(Kibibytes, "KiB", Bytes, * 1024); LL_DECLARE_DERIVED_UNIT(Mibibytes, "MiB", Kibibytes, * 1024); LL_DECLARE_DERIVED_UNIT(Gibibytes, "GiB", Mibibytes, * 1024); LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, / 8); LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bytes, * 1000 / 8); LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, * 1000 / 8); LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, * 1000 / 8); LL_DECLARE_DERIVED_UNIT(Kibibits, "Kib", Bytes, * 1024 / 8); LL_DECLARE_DERIVED_UNIT(Mibibits, "Mib", Kibibits, * 1024 / 8); LL_DECLARE_DERIVED_UNIT(Gibibits, "Gib", Mibibits, * 1024 / 8); LL_DECLARE_BASE_UNIT(Seconds, "s"); LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, * 60); LL_DECLARE_DERIVED_UNIT(Hours, "h", Seconds, * 60 * 60); LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, / 1000); LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, / 1000); LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, / 1000); LL_DECLARE_BASE_UNIT(Meters, "m"); LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, * 1000); LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, / 100); LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, / 1000); LL_DECLARE_BASE_UNIT(Hertz, "Hz"); LL_DECLARE_DERIVED_UNIT(Kilohertz, "KHz", Hertz, * 1000); LL_DECLARE_DERIVED_UNIT(Megahertz, "MHz", Kilohertz, * 1000); LL_DECLARE_DERIVED_UNIT(Gigahertz, "GHz", Megahertz, * 1000); LL_DECLARE_BASE_UNIT(Radians, "rad"); LL_DECLARE_DERIVED_UNIT(Degrees, "deg", Radians, * 0.01745329251994); } // namespace LLUnits #endif // LL_LLUNIT_H