From a7aed07a5b620977fb74e4070e432eef01d11d3c Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Tue, 27 Aug 2013 13:41:19 -0700 Subject: broke out llunit.h into llunittype.h and llunits.h for unit declarations changed unit declarations macros to make a lot more sense --- indra/llcommon/CMakeLists.txt | 3 +- indra/llcommon/llcriticaldamp.h | 2 +- indra/llcommon/lldate.h | 2 +- indra/llcommon/llerror.h | 12 +- indra/llcommon/llfasttimer.cpp | 2 +- indra/llcommon/llmemory.h | 2 +- indra/llcommon/llpreprocessor.h | 6 +- indra/llcommon/llprocessor.h | 2 +- indra/llcommon/lltimer.h | 2 +- indra/llcommon/lltraceaccumulators.h | 2 +- indra/llcommon/llunit.h | 830 ---------------------------------- indra/llcommon/llunittype.h | 734 ++++++++++++++++++++++++++++++ indra/llcommon/tests/lltrace_test.cpp | 8 +- indra/llcommon/tests/llunits_test.cpp | 73 ++- 14 files changed, 825 insertions(+), 855 deletions(-) delete mode 100644 indra/llcommon/llunit.h create mode 100644 indra/llcommon/llunittype.h (limited to 'indra/llcommon') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 62880b07f6..e138a54d29 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -209,7 +209,8 @@ set(llcommon_HEADER_FILES lltracerecording.h lltracethreadrecorder.h lltreeiterators.h - llunit.h + llunits.h + llunittype.h lluri.h lluuid.h llwin32headers.h diff --git a/indra/llcommon/llcriticaldamp.h b/indra/llcommon/llcriticaldamp.h index a02a2a0dcf..1fb6a1af29 100755 --- a/indra/llcommon/llcriticaldamp.h +++ b/indra/llcommon/llcriticaldamp.h @@ -31,7 +31,7 @@ #include #include "llframetimer.h" -#include "llunit.h" +#include "llunits.h" class LL_COMMON_API LLSmoothInterpolation { diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index aecf3b765e..be2cd2d051 100755 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -33,7 +33,7 @@ #include #include "stdtypes.h" -#include "llunit.h" +#include "llunits.h" /** * @class LLDate diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 0d6f1810d2..1ddb4874a0 100755 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -357,12 +357,12 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; #define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__) // DEPRECATED: Use the new macros that allow tags and *look* like macros. -#define lldebugs LL_COMPILE_TIME_WARNING("Warning: lldebugs deprecated, use LL_DEBUGS() instead"); LL_DEBUGS() -#define llinfos LL_COMPILE_TIME_WARNING("Warning: llinfos deprecated, use LL_INFOS() instead"); LL_INFOS() -#define llwarns LL_COMPILE_TIME_WARNING("Warning: llwarns deprecated, use LL_WARNS() instead"); LL_WARNS() -#define llerrs LL_COMPILE_TIME_WARNING("Warning: llerrs deprecated, use LL_ERRS() instead"); LL_ERRS() -#define llcont LL_COMPILE_TIME_WARNING("Warning: llcont deprecated, use LL_CONT instead"); LL_CONT -#define llendl LL_COMPILE_TIME_WARNING("Warning: llendl deprecated, use LL_ENDL instead"); LL_ENDL +#define lldebugs LL_COMPILE_TIME_MESSAGE("Warning: lldebugs deprecated, use LL_DEBUGS() instead"); LL_DEBUGS() +#define llinfos LL_COMPILE_TIME_MESSAGE("Warning: llinfos deprecated, use LL_INFOS() instead"); LL_INFOS() +#define llwarns LL_COMPILE_TIME_MESSAGE("Warning: llwarns deprecated, use LL_WARNS() instead"); LL_WARNS() +#define llerrs LL_COMPILE_TIME_MESSAGE("Warning: llerrs deprecated, use LL_ERRS() instead"); LL_ERRS() +#define llcont LL_COMPILE_TIME_MESSAGE("Warning: llcont deprecated, use LL_CONT instead"); LL_CONT +#define llendl LL_COMPILE_TIME_MESSAGE("Warning: llendl deprecated, use LL_ENDL instead"); LL_ENDL #endif // LL_LLERROR_H diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index ae3234a87a..2235eb1a08 100755 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -32,7 +32,7 @@ #include "llsingleton.h" #include "lltreeiterators.h" #include "llsdserialize.h" -#include "llunit.h" +#include "llunits.h" #include "llsd.h" #include "lltracerecording.h" #include "lltracethreadrecorder.h" diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 23be1e5b2d..d3c5e5235d 100755 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -27,7 +27,7 @@ #define LLMEMORY_H #include "linden_common.h" -#include "llunit.h" +#include "llunits.h" #if !LL_WINDOWS #include #endif diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index f00885ae2f..0fcc872690 100755 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -193,12 +193,10 @@ #define LL_TO_STRING(x) LL_TO_STRING_HELPER(x) #define LL_FILE_LINENO(msg) __FILE__ "(" LL_TO_STRING(__LINE__) ") : " msg #if LL_WINDOWS -#define LL_COMPILE_TIME_WARNING(msg) __pragma(message(LL_FILE_LINENO(msg))) -#define LL_COMPILE_TIME_ERROR(msg) static_assert(false, msg) +#define LL_COMPILE_TIME_MESSAGE(msg) __pragma(message(LL_FILE_LINENO(msg))) #else // no way to get gcc 4.2 to print a user-defined diagnostic message only when a macro is used -#define LL_COMPILE_TIME_WARNING(msg) -#define LL_COMPILE_TIME_ERROR(msg) +#define LL_COMPILE_TIME_MESSAGE(msg) #endif #endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index 4956a39700..90e5bc59ee 100755 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -27,7 +27,7 @@ #ifndef LLPROCESSOR_H #define LLPROCESSOR_H -#include "llunit.h" +#include "llunits.h" class LLProcessorInfoImpl; diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 8b3930e2fa..4e58102094 100755 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -37,7 +37,7 @@ #include #include // units conversions -#include "llunit.h" +#include "llunits.h" #ifndef USEC_PER_SEC const U32 USEC_PER_SEC = 1000000; #endif diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index bf195f72b1..e0f60800e3 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -31,7 +31,7 @@ #include "stdtypes.h" #include "llpreprocessor.h" -#include "llunit.h" +#include "llunits.h" #include "lltimer.h" #include "llrefcount.h" #include "llthreadlocalstorage.h" diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h deleted file mode 100644 index 798d97a46e..0000000000 --- a/indra/llcommon/llunit.h +++ /dev/null @@ -1,830 +0,0 @@ -/** - * @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 "llerror.h" - -//lightweight replacement of type traits for simple type equality check -template -struct LLIsSameType -{ - static const bool value = false; -}; - -template -struct LLIsSameType -{ - static const bool value = true; -}; - -// workaround for decltype() not existing and typeof() not working inline in gcc 4.2 -template -struct LLResultTypeAdd -{ - typedef LL_TYPEOF(S() + T()) type_t; -}; - -template -struct LLResultTypeSubtract -{ - typedef LL_TYPEOF(S() - T()) type_t; -}; - -template -struct LLResultTypeMultiply -{ - typedef LL_TYPEOF(S() * T()) type_t; -}; - -template -struct LLResultTypeDivide -{ - typedef LL_TYPEOF(S() / T(1)) type_t; -}; - -template -struct LLResultTypePromote -{ - typedef LL_TYPEOF((true) ? S() : T()) type_t; -}; - -template -struct LLUnit -{ - typedef LLUnit 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 - LL_FORCE_INLINE LLUnit(LLUnit other) - : mValue(convert(other).mValue) - {} - - storage_t value() const - { - return mValue; - } - - void value(storage_t value) - { - mValue = value; - } - - template - storage_t valueInUnits() - { - return LLUnit(*this).value(); - } - - template - void valueInUnits(storage_t value) - { - *this = LLUnit(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 - LL_FORCE_INLINE static self_t convert(LLUnit v) - { - typedef typename LLResultTypePromote::type_t result_storage_t; - LLUnit 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 -std::ostream& operator <<(std::ostream& s, const LLUnit& unit) -{ - s << unit.value() << UNIT_TYPE::getUnitLabel(); - return s; -} - -template -std::istream& operator >>(std::istream& s, LLUnit& unit) -{ - STORAGE_TYPE val; - s >> val; - unit.value(val); - return s; -} - -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(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 - void operator += (LLUnitImplicit 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 - void operator -= (LLUnitImplicit other) - { - base_t::mValue -= convert(other).value(); - } - -}; - -template -std::ostream& operator <<(std::ostream& s, const LLUnitImplicit& unit) -{ - s << unit.value() << UNIT_TYPE::getUnitLabel(); - return s; -} - -template -std::istream& operator >>(std::istream& s, LLUnitImplicit& unit) -{ - STORAGE_TYPE val; - s >> val; - unit = val; - return s; -} - -template -LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) -{ - S2 divisor(1); - - LL_STATIC_ASSERT((LLIsSameType::value - || !LLIsSameType::value - || !LLIsSameType::value), - "conversion requires compatible units"); - - if (LLIsSameType::value) - { - // T1 and T2 same type, just assign - out.value((S2)in.value()); - } - else if (T1::sLevel > T2::sLevel) - { - // reduce T1 - LLUnit new_in; - divisor *= (S2)ll_convert_units(in, new_in); - divisor *= (S2)ll_convert_units(new_in, out); - } - else - { - // reduce T2 - LLUnit new_out; - divisor *= (S2)ll_convert_units(in, new_out); - divisor *= (S2)ll_convert_units(new_out, out); - } - return divisor; -} - -template -struct LLStorageType -{ - typedef T type_t; -}; - -template -struct LLStorageType > -{ - 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 -LLUnit::type_t, UNIT_TYPE1> operator + (LLUnit first, LLUnit second) -{ - LLUnit::type_t, UNIT_TYPE1> result(first); - result += second; - return result; -} - -template -LLUnit operator + (LLUnit first, UNITLESS second) -{ - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); - return LLUnit(0); -} - -template -LLUnit operator + (UNITLESS first, LLUnit second) -{ - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); - return LLUnit(0); -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnitImplicit first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result += second; - return result; -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnit first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result += second; - return result; -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnitImplicit first, LLUnit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result += LLUnitImplicit(second); - return result; -} - -template -LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator + (LLUnitImplicit first, UNITLESS_TYPE second) -{ - LLUnitImplicit::type_t>::type_t, UNIT_TYPE> result(first); - result += second; - return result; -} - -template -LLUnitImplicit::type_t, STORAGE_TYPE>:: - type_t, UNIT_TYPE> operator + (UNITLESS_TYPE first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> result(first); - result += second; - return result; -} - -// -// operator - -// -template -LLUnit::type_t, UNIT_TYPE1> operator - (LLUnit first, LLUnit second) -{ - LLUnit::type_t, UNIT_TYPE1> result(first); - result -= second; - return result; -} - -template -LLUnit operator - (LLUnit first, UNITLESS second) -{ - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); - return LLUnit(0); -} - -template -LLUnit operator - (UNITLESS first, LLUnit second) -{ - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); - return LLUnit(0); -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnitImplicit first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result -= second; - return result; -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnit first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result -= second; - return result; -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnitImplicit first, LLUnit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result -= LLUnitImplicit(second); - return result; -} - -template -LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator - (LLUnitImplicit first, UNITLESS_TYPE second) -{ - LLUnitImplicit::type_t>::type_t, UNIT_TYPE> result(first); - result -= second; - return result; -} - -template -LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator - (UNITLESS_TYPE first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> result(first); - result -= second; - return result; -} - -// -// operator * -// -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 -LLUnit::type_t>::type_t, UNIT_TYPE> operator * (LLUnit first, UNITLESS_TYPE second) -{ - return LLUnit::type_t>::type_t, UNIT_TYPE>(first.value() * second); -} - -template -LLUnit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator * (UNITLESS_TYPE first, LLUnit second) -{ - return LLUnit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE>(first * second.value()); -} - -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(); -} - -template -LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator * (LLUnitImplicit first, UNITLESS_TYPE second) -{ - return LLUnitImplicit::type_t, UNIT_TYPE>(first.value() * second); -} - -template -LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator * (UNITLESS_TYPE first, LLUnitImplicit second) -{ - return LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE>(first * second.value()); -} - - -// -// operator / -// - -template -LLUnit::type_t>::type_t, UNIT_TYPE> operator / (LLUnit first, UNITLESS_TYPE second) -{ - return LLUnit::type_t>::type_t, UNIT_TYPE>(first.value() / second); -} - -template -typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnit second) -{ - return first.value() / first.convert(second).value(); -} - -template -LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator / (LLUnitImplicit first, UNITLESS_TYPE second) -{ - return LLUnitImplicit::type_t>::type_t, UNIT_TYPE>(first.value() / second); -} - -template -typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnitImplicit second) -{ - return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); -} - -template -typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnitImplicit second) -{ - return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); -} - -template -typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnit second) -{ - return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); -} - -// -// comparison operators -// - -#define LL_UNIT_DECLARE_COMPARISON_OPERATOR(op) \ -template \ -bool operator op (LLUnitImplicit first, LLUnitImplicit second) \ -{ \ - return first.value() op first.convert(second).value(); \ -} \ - \ -template \ -bool operator op (LLUnitImplicit first, UNITLESS_TYPE second) \ -{ \ - return first.value() op second; \ -} \ - \ -template \ -bool operator op (UNITLESS_TYPE first, LLUnitImplicit second) \ -{ \ - return first op second.value(); \ -} \ - \ -template \ -bool operator op (LLUnit first, LLUnit second) \ -{ \ - return first.value() op first.convert(second).value(); \ -} \ - \ -template \ -bool operator op (LLUnit first, UNITLESS_TYPE second) \ -{ \ - LL_BAD_TEMPLATE_INSTANTIATION(UNITLESS_TYPE, "operator " #op " requires compatible unit types"); \ - return false; \ -} \ - \ -template \ -bool operator op (UNITLESS_TYPE first, LLUnit second) \ -{ \ - LL_BAD_TEMPLATE_INSTANTIATION(UNITLESS_TYPE, "operator " #op " requires compatible unit types"); \ - return false; \ -} \ - \ -template \ -bool operator op (LLUnit first, LLUnitImplicit second) \ -{ \ - return first.value() op first.convert(second).value(); \ -} \ - \ -template \ -bool operator op (LLUnitImplicit first, LLUnit 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 -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(T val) - : mValue(val), - mDivisor(1) - {} - - template - self_t operator * (OTHER_T other) - { - return mValue * other; - } - - template - self_t operator / (OTHER_T other) - { - mDivisor *= other; - return *this; - } - - template - self_t operator + (OTHER_T other) - { - mValue /= mDivisor; - mValue += other; - return *this; - } - - template - self_t operator - (OTHER_T other) - { - mValue /= mDivisor; - mValue -= other; - return *this; - } - - T mValue; - T mDivisor; -}; - -template -struct LLUnitInverseLinearOps -{ - typedef LLUnitInverseLinearOps self_t; - - LLUnitInverseLinearOps(T val) - : mValue(val), - mDivisor(1) - {} - - template - self_t operator * (OTHER_T other) - { - mDivisor *= other; - return *this; - } - - template - self_t operator / (OTHER_T other) - { - mValue *= other; - return *this; - } - - template - self_t operator + (OTHER_T other) - { - mValue /= mDivisor; - mValue -= other; - return *this; - } - - template - 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 \ - static LLUnit fromValue(T value) { return LLUnit(value); } \ - template \ - static LLUnit fromValue(LLUnit value) \ - { return LLUnit(value); } \ -} - - -#define LL_DECLARE_DERIVED_UNIT(base_unit_name, conversion_operation, unit_name, unit_label) \ -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 \ - static LLUnit fromValue(T value) { return LLUnit(value); } \ - template \ - static LLUnit fromValue(LLUnit value) \ - { return LLUnit(value); } \ -}; \ - \ -template \ -LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ -{ \ - typedef typename LLResultTypePromote::type_t result_storage_t; \ - LLUnitLinearOps op = \ - LLUnitLinearOps(in.value()) conversion_operation; \ - out = LLUnit((S2)op.mValue); \ - return op.mDivisor; \ -} \ - \ -template \ -LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ -{ \ - typedef typename LLResultTypePromote::type_t result_storage_t; \ - LLUnitInverseLinearOps op = \ - LLUnitInverseLinearOps(in.value()) conversion_operation; \ - out = LLUnit((S2)op.mValue); \ - return op.mDivisor; \ -} - -#define LL_DECLARE_UNIT_TYPEDEFS(ns, unit_name) \ - typedef LLUnit F32##unit_name; \ - typedef LLUnitImplicit F32##unit_name##Implicit;\ - typedef LLUnit F64##unit_name; \ - typedef LLUnitImplicit F64##unit_name##Implicit;\ - typedef LLUnit S32##unit_name; \ - typedef LLUnitImplicit S32##unit_name##Implicit;\ - typedef LLUnit S64##unit_name; \ - typedef LLUnitImplicit S64##unit_name##Implicit;\ - typedef LLUnit U32##unit_name; \ - typedef LLUnitImplicit U32##unit_name##Implicit;\ - typedef LLUnit U64##unit_name; \ - typedef LLUnitImplicit U64##unit_name##Implicit - -// -// Unit declarations -// - -namespace LLUnits -{ -LL_DECLARE_BASE_UNIT(Bytes, "B"); -// technically, these are kibibytes, mibibytes, etc. but we should stick with commonly accepted terminology -LL_DECLARE_DERIVED_UNIT(Bytes, * 1024, Kilobytes, "KB"); -LL_DECLARE_DERIVED_UNIT(Kilobytes, * 1024, Megabytes, "MB"); -LL_DECLARE_DERIVED_UNIT(Megabytes, * 1024, Gigabytes, "GB"); -} - -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Bytes); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilobytes); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megabytes); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabytes); - -namespace LLUnits -{ -// technically, these are kibibits, mibibits, etc. but we should stick with commonly accepted terminology -LL_DECLARE_DERIVED_UNIT(Bytes, / 8, Bits, "b"); -LL_DECLARE_DERIVED_UNIT(Bits, * 1024, Kilobits, "Kb"); -LL_DECLARE_DERIVED_UNIT(Kilobits, * 1024, Megabits, "Mb"); -LL_DECLARE_DERIVED_UNIT(Megabits, * 1024, Gigabits, "Gb"); -} - -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Bits); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilobits); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megabits); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabits); - -namespace LLUnits -{ -LL_DECLARE_BASE_UNIT(Seconds, "s"); -LL_DECLARE_DERIVED_UNIT(Seconds, * 60, Minutes, "min"); -LL_DECLARE_DERIVED_UNIT(Minutes, * 60, Hours, "h"); -LL_DECLARE_DERIVED_UNIT(Hours, * 24, Days, "d"); -LL_DECLARE_DERIVED_UNIT(Seconds, / 1000, Milliseconds, "ms"); -LL_DECLARE_DERIVED_UNIT(Milliseconds, / 1000, Microseconds, "\x09\x3cs"); -LL_DECLARE_DERIVED_UNIT(Microseconds, / 1000, Nanoseconds, "ns"); -} - -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Seconds); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Minutes); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Hours); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Days); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Milliseconds); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Microseconds); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Nanoseconds); - -namespace LLUnits -{ -LL_DECLARE_BASE_UNIT(Meters, "m"); -LL_DECLARE_DERIVED_UNIT(Meters, * 1000, Kilometers, "km"); -LL_DECLARE_DERIVED_UNIT(Meters, / 100, Centimeters, "cm"); -LL_DECLARE_DERIVED_UNIT(Meters, / 1000, Millimeters, "mm"); -} - -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Meters); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilometers); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Centimeters); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Millimeters); - -namespace LLUnits -{ -// rare units -LL_DECLARE_BASE_UNIT(Hertz, "Hz"); -LL_DECLARE_DERIVED_UNIT(Hertz, * 1000, Kilohertz, "KHz"); -LL_DECLARE_DERIVED_UNIT(Kilohertz, * 1000, Megahertz, "MHz"); -LL_DECLARE_DERIVED_UNIT(Megahertz, * 1000, Gigahertz, "GHz"); - -LL_DECLARE_BASE_UNIT(Radians, "rad"); -LL_DECLARE_DERIVED_UNIT(Radians, / 57.29578f, Degrees, "deg"); - -LL_DECLARE_BASE_UNIT(Percent, "%"); -LL_DECLARE_DERIVED_UNIT(Percent, * 100, Ratio, "x"); - -LL_DECLARE_BASE_UNIT(Triangles, "tris"); -LL_DECLARE_DERIVED_UNIT(Triangles, * 1000, Kilotriangles, "ktris"); - -} // namespace LLUnits - -// rare units -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Hertz); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilohertz); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megahertz); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigahertz); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Radians); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Degrees); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Percent); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Ratio); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Triangles); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilotriangles); - - -#endif // LL_LLUNIT_H 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 +struct LLIsSameType +{ + static const bool value = false; +}; + +template +struct LLIsSameType +{ + static const bool value = true; +}; + +// workaround for decltype() not existing and typeof() not working inline in gcc 4.2 +template +struct LLResultTypeAdd +{ + typedef LL_TYPEOF(S() + T()) type_t; +}; + +template +struct LLResultTypeSubtract +{ + typedef LL_TYPEOF(S() - T()) type_t; +}; + +template +struct LLResultTypeMultiply +{ + typedef LL_TYPEOF(S() * T()) type_t; +}; + +template +struct LLResultTypeDivide +{ + typedef LL_TYPEOF(S() / T(1)) type_t; +}; + +template +struct LLResultTypePromote +{ + typedef LL_TYPEOF((true) ? S() : T()) type_t; +}; + +template +struct LLUnit +{ + typedef LLUnit 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 + LL_FORCE_INLINE LLUnit(LLUnit other) + : mValue(convert(other).mValue) + {} + + storage_t value() const + { + return mValue; + } + + void value(storage_t value) + { + mValue = value; + } + + template + storage_t valueInUnits() + { + return LLUnit(*this).value(); + } + + template + void valueInUnits(storage_t value) + { + *this = LLUnit(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 + LL_FORCE_INLINE static self_t convert(LLUnit v) + { + typedef typename LLResultTypePromote::type_t result_storage_t; + LLUnit 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 +std::ostream& operator <<(std::ostream& s, const LLUnit& unit) +{ + s << unit.value() << UNIT_TYPE::getUnitLabel(); + return s; +} + +template +std::istream& operator >>(std::istream& s, LLUnit& unit) +{ + STORAGE_TYPE val; + s >> val; + unit.value(val); + return s; +} + +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(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 + void operator += (LLUnitImplicit 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 + void operator -= (LLUnitImplicit other) + { + base_t::mValue -= convert(other).value(); + } + +}; + +template +std::ostream& operator <<(std::ostream& s, const LLUnitImplicit& unit) +{ + s << unit.value() << UNIT_TYPE::getUnitLabel(); + return s; +} + +template +std::istream& operator >>(std::istream& s, LLUnitImplicit& unit) +{ + STORAGE_TYPE val; + s >> val; + unit = val; + return s; +} + +template +LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) +{ + S2 divisor(1); + + LL_STATIC_ASSERT((LLIsSameType::value + || !LLIsSameType::value + || !LLIsSameType::value), + "conversion requires compatible units"); + + if (LLIsSameType::value) + { + // T1 and T2 same type, just assign + out.value((S2)in.value()); + } + else if (T1::sLevel > T2::sLevel) + { + // reduce T1 + LLUnit new_in; + divisor *= (S2)ll_convert_units(in, new_in); + divisor *= (S2)ll_convert_units(new_in, out); + } + else + { + // reduce T2 + LLUnit new_out; + divisor *= (S2)ll_convert_units(in, new_out); + divisor *= (S2)ll_convert_units(new_out, out); + } + return divisor; +} + +template +struct LLStorageType +{ + typedef T type_t; +}; + +template +struct LLStorageType > +{ + 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 +LLUnit::type_t, UNIT_TYPE1> operator + (LLUnit first, LLUnit second) +{ + LLUnit::type_t, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template +LLUnit operator + (LLUnit first, UNITLESS second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit(0); +} + +template +LLUnit operator + (UNITLESS first, LLUnit second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit(0); +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnitImplicit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnitImplicit first, LLUnit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result += LLUnitImplicit(second); + return result; +} + +template +LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator + (LLUnitImplicit first, UNITLESS_TYPE second) +{ + LLUnitImplicit::type_t>::type_t, UNIT_TYPE> result(first); + result += second; + return result; +} + +template +LLUnitImplicit::type_t, STORAGE_TYPE>:: + type_t, UNIT_TYPE> operator + (UNITLESS_TYPE first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> result(first); + result += second; + return result; +} + +// +// operator - +// +template +LLUnit::type_t, UNIT_TYPE1> operator - (LLUnit first, LLUnit second) +{ + LLUnit::type_t, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template +LLUnit operator - (LLUnit first, UNITLESS second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit(0); +} + +template +LLUnit operator - (UNITLESS first, LLUnit second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit(0); +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnitImplicit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnitImplicit first, LLUnit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result -= LLUnitImplicit(second); + return result; +} + +template +LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator - (LLUnitImplicit first, UNITLESS_TYPE second) +{ + LLUnitImplicit::type_t>::type_t, UNIT_TYPE> result(first); + result -= second; + return result; +} + +template +LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator - (UNITLESS_TYPE first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> result(first); + result -= second; + return result; +} + +// +// operator * +// +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 +LLUnit::type_t>::type_t, UNIT_TYPE> operator * (LLUnit first, UNITLESS_TYPE second) +{ + return LLUnit::type_t>::type_t, UNIT_TYPE>(first.value() * second); +} + +template +LLUnit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator * (UNITLESS_TYPE first, LLUnit second) +{ + return LLUnit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE>(first * second.value()); +} + +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(); +} + +template +LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator * (LLUnitImplicit first, UNITLESS_TYPE second) +{ + return LLUnitImplicit::type_t, UNIT_TYPE>(first.value() * second); +} + +template +LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator * (UNITLESS_TYPE first, LLUnitImplicit second) +{ + return LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE>(first * second.value()); +} + + +// +// operator / +// + +template +LLUnit::type_t>::type_t, UNIT_TYPE> operator / (LLUnit first, UNITLESS_TYPE second) +{ + return LLUnit::type_t>::type_t, UNIT_TYPE>(first.value() / second); +} + +template +typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnit second) +{ + return first.value() / first.convert(second).value(); +} + +template +LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator / (LLUnitImplicit first, UNITLESS_TYPE second) +{ + return LLUnitImplicit::type_t>::type_t, UNIT_TYPE>(first.value() / second); +} + +template +typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnitImplicit second) +{ + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); +} + +template +typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnitImplicit second) +{ + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); +} + +template +typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnit second) +{ + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); +} + +// +// comparison operators +// + +#define LL_UNIT_DECLARE_COMPARISON_OPERATOR(op) \ +template \ +bool operator op (LLUnitImplicit first, LLUnitImplicit second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} \ + \ +template \ +bool operator op (LLUnitImplicit first, UNITLESS_TYPE second) \ +{ \ + return first.value() op second; \ +} \ + \ +template \ +bool operator op (UNITLESS_TYPE first, LLUnitImplicit second) \ +{ \ + return first op second.value(); \ +} \ + \ +template \ +bool operator op (LLUnit first, LLUnit second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} \ + \ +template \ +bool operator op (LLUnit first, UNITLESS_TYPE second) \ +{ \ + LL_BAD_TEMPLATE_INSTANTIATION(UNITLESS_TYPE, "operator " #op " requires compatible unit types"); \ + return false; \ +} \ + \ +template \ +bool operator op (UNITLESS_TYPE first, LLUnit second) \ +{ \ + LL_BAD_TEMPLATE_INSTANTIATION(UNITLESS_TYPE, "operator " #op " requires compatible unit types"); \ + return false; \ +} \ + \ +template \ +bool operator op (LLUnit first, LLUnitImplicit second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} \ + \ +template \ +bool operator op (LLUnitImplicit first, LLUnit 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 +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(T val) + : mValue(val), + mDivisor(1) + {} + + template + self_t operator * (OTHER_T other) + { + return mValue * other; + } + + template + self_t operator / (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template + self_t operator + (OTHER_T other) + { + mValue /= mDivisor; + mValue += other; + return *this; + } + + template + self_t operator - (OTHER_T other) + { + mValue /= mDivisor; + mValue -= other; + return *this; + } + + T mValue; + T mDivisor; +}; + +template +struct LLUnitInverseLinearOps +{ + typedef LLUnitInverseLinearOps self_t; + + LLUnitInverseLinearOps(T val) + : mValue(val), + mDivisor(1) + {} + + template + self_t operator * (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template + self_t operator / (OTHER_T other) + { + mValue *= other; + return *this; + } + + template + self_t operator + (OTHER_T other) + { + mValue /= mDivisor; + mValue -= other; + return *this; + } + + template + 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 \ + static LLUnit fromValue(T value) { return LLUnit(value); } \ + template \ + static LLUnit fromValue(LLUnit value) \ + { return LLUnit(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 \ + static LLUnit fromValue(T value) { return LLUnit(value); } \ + template \ + static LLUnit fromValue(LLUnit value) \ + { return LLUnit(value); } \ +}; \ + \ +template \ +LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ +{ \ + typedef typename LLResultTypePromote::type_t result_storage_t; \ + LLUnitInverseLinearOps op = \ + LLUnitInverseLinearOps(in.value()) conversion_operation; \ + out = LLUnit((S2)op.mValue); \ + return op.mDivisor; \ +} \ + \ +template \ +LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ +{ \ + typedef typename LLResultTypePromote::type_t result_storage_t; \ + LLUnitLinearOps op = \ + LLUnitLinearOps(in.value()) conversion_operation; \ + out = LLUnit((S2)op.mValue); \ + return op.mDivisor; \ +} + +#define LL_DECLARE_UNIT_TYPEDEFS(ns, unit_name) \ + typedef LLUnit F32##unit_name; \ + typedef LLUnitImplicit F32##unit_name##Implicit;\ + typedef LLUnit F64##unit_name; \ + typedef LLUnitImplicit F64##unit_name##Implicit;\ + typedef LLUnit S32##unit_name; \ + typedef LLUnitImplicit S32##unit_name##Implicit;\ + typedef LLUnit S64##unit_name; \ + typedef LLUnitImplicit S64##unit_name##Implicit;\ + typedef LLUnit U32##unit_name; \ + typedef LLUnitImplicit U32##unit_name##Implicit;\ + typedef LLUnit U64##unit_name; \ + typedef LLUnitImplicit U64##unit_name##Implicit + +#endif //LL_UNITTYPE_H diff --git a/indra/llcommon/tests/lltrace_test.cpp b/indra/llcommon/tests/lltrace_test.cpp index 1c2a4528ae..8ce509699d 100644 --- a/indra/llcommon/tests/lltrace_test.cpp +++ b/indra/llcommon/tests/lltrace_test.cpp @@ -36,12 +36,12 @@ namespace LLUnits { // using powers of 2 to allow strict floating point equality LL_DECLARE_BASE_UNIT(Ounces, "oz"); - LL_DECLARE_DERIVED_UNIT(Ounces, * 12, TallCup, ""); - LL_DECLARE_DERIVED_UNIT(Ounces, * 16, GrandeCup, ""); - LL_DECLARE_DERIVED_UNIT(Ounces, * 20, VentiCup, ""); + LL_DECLARE_DERIVED_UNIT(TallCup, "", Ounces, / 12); + LL_DECLARE_DERIVED_UNIT(GrandeCup, "", Ounces, / 16); + LL_DECLARE_DERIVED_UNIT(VentiCup, "", Ounces, / 20); LL_DECLARE_BASE_UNIT(Grams, "g"); - LL_DECLARE_DERIVED_UNIT(Grams, / 1000, Milligrams, "mg"); + LL_DECLARE_DERIVED_UNIT(Milligrams, "mg", Grams, * 1000); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Ounces); diff --git a/indra/llcommon/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp index 31d4f86159..5a18603e4e 100644 --- a/indra/llcommon/tests/llunits_test.cpp +++ b/indra/llcommon/tests/llunits_test.cpp @@ -27,15 +27,15 @@ #include "linden_common.h" -#include "llunit.h" +#include "llunits.h" #include "../test/lltut.h" namespace LLUnits { // using powers of 2 to allow strict floating point equality LL_DECLARE_BASE_UNIT(Quatloos, "Quat"); - LL_DECLARE_DERIVED_UNIT(Quatloos, * 4, Latinum, "Lat"); - LL_DECLARE_DERIVED_UNIT(Latinum, / 16, Solari, "Sol"); + LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, / 4); + LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, * 16); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Quatloos); @@ -256,6 +256,12 @@ namespace tut // conversion of implicits LLUnitImplicit latinum_implicit(2); ensure("implicit units of different types are comparable", latinum_implicit * 2 == quatloos_implicit); + + quatloos_implicit += F32Quatloos(10); + ensure("can add-assign explicit units", quatloos_implicit == 26); + + quatloos_implicit -= F32Quatloos(10); + ensure("can subtract-assign explicit units", quatloos_implicit == 16); } // precision tests @@ -272,4 +278,65 @@ namespace tut mega_bytes = (U32Megabytes)5 + (S32Megabytes)-1; ensure("can mix unsigned and signed in units addition", mega_bytes == (S32Megabytes)4); } + + // default units + template<> template<> + void units_object_t::test<9>() + { + U32Gigabytes GB(1); + U32Megabytes MB(GB); + U32Kilobytes KB(GB); + U32Bytes B(GB); + + ensure("GB -> MB conversion", MB.value() == 1024); + ensure("GB -> KB conversion", KB.value() == 1024 * 1024); + ensure("GB -> B conversion", B.value() == 1024 * 1024 * 1024); + + KB = U32Kilobytes(1); + U32Kilobits Kb(KB); + U32Bits b(KB); + ensure("KB -> Kb conversion", Kb.value() == 8); + ensure("KB -> b conversion", b.value() == 8 * 1024); + + U32Days days(1); + U32Hours hours(days); + U32Minutes minutes(days); + U32Seconds seconds(days); + U32Milliseconds ms(days); + + ensure("days -> hours conversion", hours.value() == 24); + ensure("days -> minutes conversion", minutes.value() == 24 * 60); + ensure("days -> seconds conversion", seconds.value() == 24 * 60 * 60); + ensure("days -> ms conversion", ms.value() == 24 * 60 * 60 * 1000); + + U32Kilometers km(1); + U32Meters m(km); + U32Centimeters cm(km); + U32Millimeters mm(km); + + ensure("km -> m conversion", m.value() == 1000); + ensure("km -> cm conversion", cm.value() == 1000 * 100); + ensure("km -> mm conversion", mm.value() == 1000 * 1000); + + U32Gigahertz GHz(1); + U32Megahertz MHz(GHz); + U32Kilohertz KHz(GHz); + U32Hertz Hz(GHz); + + ensure("GHz -> MHz conversion", MHz.value() == 1000); + ensure("GHz -> KHz conversion", KHz.value() == 1000 * 1000); + ensure("GHz -> Hz conversion", Hz.value() == 1000 * 1000 * 1000); + + F32Radians rad(6.2831853071795f); + F32Degrees deg(rad); + ensure("radians -> degrees conversion", deg.value() > 359 && deg.value() < 361); + + F32Percent percent(50); + F32Ratio ratio(percent); + ensure("percent -> ratio conversion", ratio.value() == 0.5f); + + U32Kilotriangles ktris(1); + U32Triangles tris(ktris); + ensure("kilotriangles -> triangles conversion", tris.value() == 1000); + } } -- cgit v1.2.3