cannam@49: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors cannam@49: // Licensed under the MIT License: cannam@49: // cannam@49: // Permission is hereby granted, free of charge, to any person obtaining a copy cannam@49: // of this software and associated documentation files (the "Software"), to deal cannam@49: // in the Software without restriction, including without limitation the rights cannam@49: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell cannam@49: // copies of the Software, and to permit persons to whom the Software is cannam@49: // furnished to do so, subject to the following conditions: cannam@49: // cannam@49: // The above copyright notice and this permission notice shall be included in cannam@49: // all copies or substantial portions of the Software. cannam@49: // cannam@49: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR cannam@49: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, cannam@49: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE cannam@49: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER cannam@49: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, cannam@49: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN cannam@49: // THE SOFTWARE. cannam@49: cannam@49: // This file contains types which are intended to help detect incorrect usage at compile cannam@49: // time, but should then be optimized down to basic primitives (usually, integers) by the cannam@49: // compiler. cannam@49: cannam@49: #ifndef KJ_UNITS_H_ cannam@49: #define KJ_UNITS_H_ cannam@49: cannam@49: #if defined(__GNUC__) && !KJ_HEADER_WARNINGS cannam@49: #pragma GCC system_header cannam@49: #endif cannam@49: cannam@49: #include "common.h" cannam@49: cannam@49: namespace kj { cannam@49: cannam@49: // ======================================================================================= cannam@49: // IDs cannam@49: cannam@49: template cannam@49: struct Id { cannam@49: // A type-safe numeric ID. `UnderlyingType` is the underlying integer representation. `Label` cannam@49: // distinguishes this Id from other Id types. Sample usage: cannam@49: // cannam@49: // class Foo; cannam@49: // typedef Id FooId; cannam@49: // cannam@49: // class Bar; cannam@49: // typedef Id BarId; cannam@49: // cannam@49: // You can now use the FooId and BarId types without any possibility of accidentally using a cannam@49: // FooId when you really wanted a BarId or vice-versa. cannam@49: cannam@49: UnderlyingType value; cannam@49: cannam@49: inline constexpr Id(): value(0) {} cannam@49: inline constexpr explicit Id(int value): value(value) {} cannam@49: cannam@49: inline constexpr bool operator==(const Id& other) const { return value == other.value; } cannam@49: inline constexpr bool operator!=(const Id& other) const { return value != other.value; } cannam@49: inline constexpr bool operator<=(const Id& other) const { return value <= other.value; } cannam@49: inline constexpr bool operator>=(const Id& other) const { return value >= other.value; } cannam@49: inline constexpr bool operator< (const Id& other) const { return value < other.value; } cannam@49: inline constexpr bool operator> (const Id& other) const { return value > other.value; } cannam@49: }; cannam@49: cannam@49: // ======================================================================================= cannam@49: // Quantity and UnitRatio -- implement unit analysis via the type system cannam@49: cannam@49: template constexpr bool isIntegral() { return false; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: template <> constexpr bool isIntegral() { return true; } cannam@49: cannam@49: template cannam@49: class UnitRatio { cannam@49: // A multiplier used to convert Quantities of one unit to Quantities of another unit. See cannam@49: // Quantity, below. cannam@49: // cannam@49: // Construct this type by dividing one Quantity by another of a different unit. Use this type cannam@49: // by multiplying it by a Quantity, or dividing a Quantity by it. cannam@49: cannam@49: static_assert(isIntegral(), "Underlying type for UnitRatio must be integer."); cannam@49: cannam@49: public: cannam@49: inline UnitRatio() {} cannam@49: cannam@49: constexpr explicit UnitRatio(Number unit1PerUnit2): unit1PerUnit2(unit1PerUnit2) {} cannam@49: // This constructor was intended to be private, but GCC complains about it being private in a cannam@49: // bunch of places that don't appear to even call it, so I made it public. Oh well. cannam@49: cannam@49: template cannam@49: inline constexpr UnitRatio(const UnitRatio& other) cannam@49: : unit1PerUnit2(other.unit1PerUnit2) {} cannam@49: cannam@49: template cannam@49: inline constexpr UnitRatio cannam@49: operator+(UnitRatio other) const { cannam@49: return UnitRatio( cannam@49: unit1PerUnit2 + other.unit1PerUnit2); cannam@49: } cannam@49: template cannam@49: inline constexpr UnitRatio cannam@49: operator-(UnitRatio other) const { cannam@49: return UnitRatio( cannam@49: unit1PerUnit2 - other.unit1PerUnit2); cannam@49: } cannam@49: cannam@49: template cannam@49: inline constexpr UnitRatio cannam@49: operator*(UnitRatio other) const { cannam@49: // U1 / U2 * U3 / U1 = U3 / U2 cannam@49: return UnitRatio( cannam@49: unit1PerUnit2 * other.unit1PerUnit2); cannam@49: } cannam@49: template cannam@49: inline constexpr UnitRatio cannam@49: operator*(UnitRatio other) const { cannam@49: // U1 / U2 * U2 / U3 = U1 / U3 cannam@49: return UnitRatio( cannam@49: unit1PerUnit2 * other.unit1PerUnit2); cannam@49: } cannam@49: cannam@49: template cannam@49: inline constexpr UnitRatio cannam@49: operator/(UnitRatio other) const { cannam@49: // (U1 / U2) / (U1 / U3) = U3 / U2 cannam@49: return UnitRatio( cannam@49: unit1PerUnit2 / other.unit1PerUnit2); cannam@49: } cannam@49: template cannam@49: inline constexpr UnitRatio cannam@49: operator/(UnitRatio other) const { cannam@49: // (U1 / U2) / (U3 / U2) = U1 / U3 cannam@49: return UnitRatio( cannam@49: unit1PerUnit2 / other.unit1PerUnit2); cannam@49: } cannam@49: cannam@49: template cannam@49: inline decltype(Number(1) / OtherNumber(1)) cannam@49: operator/(UnitRatio other) const { cannam@49: return unit1PerUnit2 / other.unit1PerUnit2; cannam@49: } cannam@49: cannam@49: inline bool operator==(UnitRatio other) const { return unit1PerUnit2 == other.unit1PerUnit2; } cannam@49: inline bool operator!=(UnitRatio other) const { return unit1PerUnit2 != other.unit1PerUnit2; } cannam@49: cannam@49: private: cannam@49: Number unit1PerUnit2; cannam@49: cannam@49: template cannam@49: friend class Quantity; cannam@49: template cannam@49: friend class UnitRatio; cannam@49: cannam@49: template cannam@49: friend inline constexpr UnitRatio cannam@49: operator*(N1, UnitRatio); cannam@49: }; cannam@49: cannam@49: template cannam@49: inline constexpr UnitRatio cannam@49: operator*(N1 n, UnitRatio r) { cannam@49: return UnitRatio(n * r.unit1PerUnit2); cannam@49: } cannam@49: cannam@49: template cannam@49: class Quantity { cannam@49: // A type-safe numeric quantity, specified in terms of some unit. Two Quantities cannot be used cannam@49: // in arithmetic unless they use the same unit. The `Unit` type parameter is only used to prevent cannam@49: // accidental mixing of units; this type is never instantiated and can very well be incomplete. cannam@49: // `Number` is the underlying primitive numeric type. cannam@49: // cannam@49: // Quantities support most basic arithmetic operators, intelligently handling units, and cannam@49: // automatically casting the underlying type in the same way that the compiler would. cannam@49: // cannam@49: // To convert a primitive number to a Quantity, multiply it by unit>(). cannam@49: // To convert a Quantity to a primitive number, divide it by unit>(). cannam@49: // To convert a Quantity of one unit to another unit, multiply or divide by a UnitRatio. cannam@49: // cannam@49: // The Quantity class is not well-suited to hardcore physics as it does not allow multiplying cannam@49: // one quantity by another. For example, multiplying meters by meters won't get you square cannam@49: // meters; it will get you a compiler error. It would be interesting to see if template cannam@49: // metaprogramming could properly deal with such things but this isn't needed for the present cannam@49: // use case. cannam@49: // cannam@49: // Sample usage: cannam@49: // cannam@49: // class SecondsLabel; cannam@49: // typedef Quantity Seconds; cannam@49: // constexpr Seconds SECONDS = unit(); cannam@49: // cannam@49: // class MinutesLabel; cannam@49: // typedef Quantity Minutes; cannam@49: // constexpr Minutes MINUTES = unit(); cannam@49: // cannam@49: // constexpr UnitRatio SECONDS_PER_MINUTE = cannam@49: // 60 * SECONDS / MINUTES; cannam@49: // cannam@49: // void waitFor(Seconds seconds) { cannam@49: // sleep(seconds / SECONDS); cannam@49: // } cannam@49: // void waitFor(Minutes minutes) { cannam@49: // waitFor(minutes * SECONDS_PER_MINUTE); cannam@49: // } cannam@49: // cannam@49: // void waitThreeMinutes() { cannam@49: // waitFor(3 * MINUTES); cannam@49: // } cannam@49: cannam@49: static_assert(isIntegral(), "Underlying type for Quantity must be integer."); cannam@49: cannam@49: public: cannam@49: inline constexpr Quantity() {} cannam@49: cannam@49: inline constexpr Quantity(MaxValue_): value(maxValue) {} cannam@49: inline constexpr Quantity(MinValue_): value(minValue) {} cannam@49: // Allow initialization from maxValue and minValue. cannam@49: // TODO(msvc): decltype(maxValue) and decltype(minValue) deduce unknown-type for these function cannam@49: // parameters, causing the compiler to complain of a duplicate constructor definition, so we cannam@49: // specify MaxValue_ and MinValue_ types explicitly. cannam@49: cannam@49: inline explicit constexpr Quantity(Number value): value(value) {} cannam@49: // This constructor was intended to be private, but GCC complains about it being private in a cannam@49: // bunch of places that don't appear to even call it, so I made it public. Oh well. cannam@49: cannam@49: template cannam@49: inline constexpr Quantity(const Quantity& other) cannam@49: : value(other.value) {} cannam@49: cannam@49: template cannam@49: inline constexpr Quantity cannam@49: operator+(const Quantity& other) const { cannam@49: return Quantity(value + other.value); cannam@49: } cannam@49: template cannam@49: inline constexpr Quantity cannam@49: operator-(const Quantity& other) const { cannam@49: return Quantity(value - other.value); cannam@49: } cannam@49: template cannam@49: inline constexpr Quantity cannam@49: operator*(OtherNumber other) const { cannam@49: static_assert(isIntegral(), "Multiplied Quantity by non-integer."); cannam@49: return Quantity(value * other); cannam@49: } cannam@49: template cannam@49: inline constexpr Quantity cannam@49: operator/(OtherNumber other) const { cannam@49: static_assert(isIntegral(), "Divided Quantity by non-integer."); cannam@49: return Quantity(value / other); cannam@49: } cannam@49: template cannam@49: inline constexpr decltype(Number(1) / OtherNumber(1)) cannam@49: operator/(const Quantity& other) const { cannam@49: return value / other.value; cannam@49: } cannam@49: template cannam@49: inline constexpr decltype(Number(1) % OtherNumber(1)) cannam@49: operator%(const Quantity& other) const { cannam@49: return value % other.value; cannam@49: } cannam@49: cannam@49: template cannam@49: inline constexpr Quantity cannam@49: operator*(const UnitRatio& ratio) const { cannam@49: return Quantity( cannam@49: value * ratio.unit1PerUnit2); cannam@49: } cannam@49: template cannam@49: inline constexpr Quantity cannam@49: operator/(const UnitRatio& ratio) const { cannam@49: return Quantity( cannam@49: value / ratio.unit1PerUnit2); cannam@49: } cannam@49: template cannam@49: inline constexpr Quantity cannam@49: operator%(const UnitRatio& ratio) const { cannam@49: return Quantity( cannam@49: value % ratio.unit1PerUnit2); cannam@49: } cannam@49: template cannam@49: inline constexpr UnitRatio cannam@49: operator/(const Quantity& other) const { cannam@49: return UnitRatio(value / other.value); cannam@49: } cannam@49: cannam@49: template cannam@49: inline constexpr bool operator==(const Quantity& other) const { cannam@49: return value == other.value; cannam@49: } cannam@49: template cannam@49: inline constexpr bool operator!=(const Quantity& other) const { cannam@49: return value != other.value; cannam@49: } cannam@49: template cannam@49: inline constexpr bool operator<=(const Quantity& other) const { cannam@49: return value <= other.value; cannam@49: } cannam@49: template cannam@49: inline constexpr bool operator>=(const Quantity& other) const { cannam@49: return value >= other.value; cannam@49: } cannam@49: template cannam@49: inline constexpr bool operator<(const Quantity& other) const { cannam@49: return value < other.value; cannam@49: } cannam@49: template cannam@49: inline constexpr bool operator>(const Quantity& other) const { cannam@49: return value > other.value; cannam@49: } cannam@49: cannam@49: template cannam@49: inline Quantity& operator+=(const Quantity& other) { cannam@49: value += other.value; cannam@49: return *this; cannam@49: } cannam@49: template cannam@49: inline Quantity& operator-=(const Quantity& other) { cannam@49: value -= other.value; cannam@49: return *this; cannam@49: } cannam@49: template cannam@49: inline Quantity& operator*=(OtherNumber other) { cannam@49: value *= other; cannam@49: return *this; cannam@49: } cannam@49: template cannam@49: inline Quantity& operator/=(OtherNumber other) { cannam@49: value /= other.value; cannam@49: return *this; cannam@49: } cannam@49: cannam@49: private: cannam@49: Number value; cannam@49: cannam@49: template cannam@49: friend class Quantity; cannam@49: cannam@49: template cannam@49: friend inline constexpr auto operator*(Number1 a, Quantity b) cannam@49: -> Quantity; cannam@49: cannam@49: template cannam@49: friend inline constexpr T unit(); cannam@49: }; cannam@49: cannam@49: template cannam@49: inline constexpr T unit() { return T(1); } cannam@49: // unit>() returns a Quantity of value 1. It also, intentionally, works on basic cannam@49: // numeric types. cannam@49: cannam@49: template cannam@49: inline constexpr auto operator*(Number1 a, Quantity b) cannam@49: -> Quantity { cannam@49: return Quantity(a * b.value); cannam@49: } cannam@49: cannam@49: template cannam@49: inline constexpr auto operator*(UnitRatio ratio, cannam@49: Quantity measure) cannam@49: -> decltype(measure * ratio) { cannam@49: return measure * ratio; cannam@49: } cannam@49: cannam@49: // ======================================================================================= cannam@49: // Absolute measures cannam@49: cannam@49: template cannam@49: class Absolute { cannam@49: // Wraps some other value -- typically a Quantity -- but represents a value measured based on cannam@49: // some absolute origin. For example, if `Duration` is a type representing a time duration, cannam@49: // Absolute might be a calendar date. cannam@49: // cannam@49: // Since Absolute represents measurements relative to some arbitrary origin, the only sensible cannam@49: // arithmetic to perform on them is addition and subtraction. cannam@49: cannam@49: // TODO(someday): Do the same automatic expansion of integer width that Quantity does? Doesn't cannam@49: // matter for our time use case, where we always use 64-bit anyway. Note that fixing this cannam@49: // would implicitly allow things like multiplying an Absolute by a UnitRatio to change its cannam@49: // units, which is actually totally logical and kind of neat. cannam@49: cannam@49: public: cannam@49: inline constexpr Absolute operator+(const T& other) const { return Absolute(value + other); } cannam@49: inline constexpr Absolute operator-(const T& other) const { return Absolute(value - other); } cannam@49: inline constexpr T operator-(const Absolute& other) const { return value - other.value; } cannam@49: cannam@49: inline Absolute& operator+=(const T& other) { value += other; return *this; } cannam@49: inline Absolute& operator-=(const T& other) { value -= other; return *this; } cannam@49: cannam@49: inline constexpr bool operator==(const Absolute& other) const { return value == other.value; } cannam@49: inline constexpr bool operator!=(const Absolute& other) const { return value != other.value; } cannam@49: inline constexpr bool operator<=(const Absolute& other) const { return value <= other.value; } cannam@49: inline constexpr bool operator>=(const Absolute& other) const { return value >= other.value; } cannam@49: inline constexpr bool operator< (const Absolute& other) const { return value < other.value; } cannam@49: inline constexpr bool operator> (const Absolute& other) const { return value > other.value; } cannam@49: cannam@49: private: cannam@49: T value; cannam@49: cannam@49: explicit constexpr Absolute(T value): value(value) {} cannam@49: cannam@49: template cannam@49: friend inline constexpr U origin(); cannam@49: }; cannam@49: cannam@49: template cannam@49: inline constexpr Absolute operator+(const T& a, const Absolute& b) { cannam@49: return b + a; cannam@49: } cannam@49: cannam@49: template struct UnitOf_ { typedef T Type; }; cannam@49: template struct UnitOf_> { typedef T Type; }; cannam@49: template cannam@49: using UnitOf = typename UnitOf_::Type; cannam@49: // UnitOf> is T. UnitOf is AnythingElse. cannam@49: cannam@49: template cannam@49: inline constexpr T origin() { return T(0 * unit>()); } cannam@49: // origin>() returns an Absolute of value 0. It also, intentionally, works on basic cannam@49: // numeric types. cannam@49: cannam@49: } // namespace kj cannam@49: cannam@49: #endif // KJ_UNITS_H_