phoenix-firestorm/indra/llcommon/llunit.h

477 lines
19 KiB
C++

/**
* @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