summaryrefslogtreecommitdiff
path: root/indra/llcommon/llunit.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llunit.h')
-rw-r--r--indra/llcommon/llunit.h481
1 files changed, 481 insertions, 0 deletions
diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h
new file mode 100644
index 0000000000..a5406fb3f0
--- /dev/null
+++ b/indra/llcommon/llunit.h
@@ -0,0 +1,481 @@
+/**
+ * @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 DERIVED_UNITS_TAG, typename BASE_UNITS_TAG, typename VALUE_TYPE>
+struct ConversionFactor
+{
+ static F64 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 F64 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(!=)
+
+
+template<typename T>
+struct LLGetUnitLabel
+{
+ static const char* getUnitLabel() { return ""; }
+};
+
+template<typename T, typename STORAGE_T>
+struct LLGetUnitLabel<LLUnit<T, STORAGE_T> >
+{
+ static const char* getUnitLabel() { return T::getUnitLabel(); }
+};
+
+//
+// Unit declarations
+//
+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(); }
+
+#define LL_DECLARE_DERIVED_UNIT(conversion_factor, base_unit_name, unit_name, unit_label) \
+struct unit_name \
+{ \
+ typedef base_unit_name base_unit_t; \
+ static const char* getUnitLabel() { return unit_label; } \
+}; \
+template<typename STORAGE_TYPE> \
+struct ConversionFactor<unit_name, base_unit_name, STORAGE_TYPE> \
+{ \
+ static F64 get() \
+ { \
+ return (F64)conversion_factor; \
+ } \
+}; \
+ \
+template<typename STORAGE_TYPE> \
+struct ConversionFactor<base_unit_name, unit_name, STORAGE_TYPE> \
+{ \
+ static F64 get() \
+ { \
+ return (F64)(1.0 / (conversion_factor)); \
+ } \
+}
+
+#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; }}
+
+LL_DECLARE_BASE_UNIT(Bytes, "B");
+LL_DECLARE_DERIVED_UNIT(1024, Bytes, Kibibytes, "KiB");
+LL_DECLARE_DERIVED_UNIT(1024 * 1024, Bytes, Mibibytes, "MiB");
+LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024, Bytes, Gibibytes, "GiB");
+LL_DECLARE_DERIVED_UNIT(1.0 / 8.0, Bytes, Bits, "b");
+LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Kibibits, "Kib");
+LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Mibibits, "Mib");
+LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024 / 8, Bytes, Gibibits, "Gib");
+
+LL_DECLARE_BASE_UNIT(Seconds, "s");
+LL_DECLARE_DERIVED_UNIT(60, Seconds, Minutes, "min");
+LL_DECLARE_DERIVED_UNIT(60 * 60, Seconds, Hours, "h");
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Seconds, Milliseconds, "ms");
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000000.0, Seconds, Microseconds, "\x09\x3cs");
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000000000.0, Seconds, Nanoseconds, "ns");
+
+LL_DECLARE_BASE_UNIT(Meters, "m");
+LL_DECLARE_DERIVED_UNIT(1000, Meters, Kilometers, "km");
+LL_DECLARE_DERIVED_UNIT(1.0 / 100.0, Meters, Centimeters, "cm");
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Meters, Millimeters, "mm");
+
+LL_DECLARE_BASE_UNIT(Hertz, "Hz");
+LL_DECLARE_DERIVED_UNIT(1000, Hertz, Kilohertz, "KHz");
+LL_DECLARE_DERIVED_UNIT(1000 * 1000, Hertz, Megahertz, "MHz");
+LL_DECLARE_DERIVED_UNIT(1000 * 1000 * 1000, Hertz, Gigahertz, "GHz");
+
+LL_DECLARE_BASE_UNIT(Radians, "rad");
+LL_DECLARE_DERIVED_UNIT(DEG_TO_RAD, Radians, Degrees, "deg");
+
+
+} // namespace LLUnits
+
+#endif // LL_LLUNIT_H