// Copyright (c) 2013, Kenton Varda // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This file contains types which are intended to help detect incorrect usage at compile // time, but should then be optimized down to basic primitives (usually, integers) by the // compiler. #ifndef KJ_UNITS_H_ #define KJ_UNITS_H_ #include "common.h" namespace kj { // ======================================================================================= // IDs template struct Id { // A type-safe numeric ID. `UnderlyingType` is the underlying integer representation. `Label` // distinguishes this Id from other Id types. Sample usage: // // class Foo; // typedef Id FooId; // // class Bar; // typedef Id BarId; // // You can now use the FooId and BarId types without any possibility of accidentally using a // FooId when you really wanted a BarId or vice-versa. UnderlyingType value; inline constexpr Id(): value(0) {} inline constexpr explicit Id(int value): value(value) {} inline constexpr bool operator==(const Id& other) { return value == other.value; } inline constexpr bool operator!=(const Id& other) { return value != other.value; } inline constexpr bool operator<=(const Id& other) { return value <= other.value; } inline constexpr bool operator>=(const Id& other) { return value >= other.value; } inline constexpr bool operator< (const Id& other) { return value < other.value; } inline constexpr bool operator> (const Id& other) { return value > other.value; } }; // ======================================================================================= // Quantity and UnitRatio -- implement unit analysis via the type system template constexpr bool isIntegral() { return false; } template <> constexpr bool isIntegral() { return true; } template <> constexpr bool isIntegral() { return true; } template <> constexpr bool isIntegral() { return true; } template <> constexpr bool isIntegral() { return true; } template <> constexpr bool isIntegral() { return true; } template <> constexpr bool isIntegral() { return true; } template <> constexpr bool isIntegral() { return true; } template <> constexpr bool isIntegral() { return true; } template <> constexpr bool isIntegral() { return true; } template <> constexpr bool isIntegral() { return true; } template <> constexpr bool isIntegral() { return true; } template class UnitRatio { // A multiplier used to convert Quantities of one unit to Quantities of another unit. See // Quantity, below. // // Construct this type by dividing one Quantity by another of a different unit. Use this type // by multiplying it by a Quantity, or dividing a Quantity by it. static_assert(isIntegral(), "Underlying type for UnitRatio must be integer."); public: inline UnitRatio() {} constexpr explicit UnitRatio(Number unit1PerUnit2): unit1PerUnit2(unit1PerUnit2) {} // This constructor was intended to be private, but GCC complains about it being private in a // bunch of places that don't appear to even call it, so I made it public. Oh well. template inline constexpr UnitRatio(const UnitRatio& other) : unit1PerUnit2(other.unit1PerUnit2) {} template inline constexpr UnitRatio operator+(UnitRatio other) { return UnitRatio( unit1PerUnit2 + other.unit1PerUnit2); } template inline constexpr UnitRatio operator-(UnitRatio other) { return UnitRatio( unit1PerUnit2 - other.unit1PerUnit2); } template inline constexpr UnitRatio operator*(UnitRatio other) { // U1 / U2 * U3 / U1 = U3 / U2 return UnitRatio( unit1PerUnit2 * other.unit1PerUnit2); } template inline constexpr UnitRatio operator*(UnitRatio other) { // U1 / U2 * U2 / U3 = U1 / U3 return UnitRatio( unit1PerUnit2 * other.unit1PerUnit2); } template inline constexpr UnitRatio operator/(UnitRatio other) { // (U1 / U2) / (U1 / U3) = U3 / U2 return UnitRatio( unit1PerUnit2 / other.unit1PerUnit2); } template inline constexpr UnitRatio operator/(UnitRatio other) { // (U1 / U2) / (U3 / U2) = U1 / U3 return UnitRatio( unit1PerUnit2 / other.unit1PerUnit2); } template inline decltype(Number(1) / OtherNumber(1)) operator/(UnitRatio other) const { return unit1PerUnit2 / other.unit1PerUnit2; } inline bool operator==(UnitRatio other) const { return unit1PerUnit2 == other.unit1PerUnit2; } inline bool operator!=(UnitRatio other) const { return unit1PerUnit2 != other.unit1PerUnit2; } private: Number unit1PerUnit2; template friend class Quantity; template friend class UnitRatio; template friend inline constexpr UnitRatio operator*(N1, UnitRatio); }; template inline constexpr UnitRatio operator*(N1 n, UnitRatio r) { return UnitRatio(n * r.unit1PerUnit2); } template class Quantity { // A type-safe numeric quantity, specified in terms of some unit. Two Quantities cannot be used // in arithmetic unless they use the same unit. The `Unit` type parameter is only used to prevent // accidental mixing of units; this type is never instantiated and can very well be incomplete. // `Number` is the underlying primitive numeric type. // // Quantities support most basic arithmetic operators, intelligently handling units, and // automatically casting the underlying type in the same way that the compiler would. // // To convert a primitive number to a Quantity, multiply it by unit>(). // To convert a Quantity to a primitive number, divide it by unit>(). // To convert a Quantity of one unit to another unit, multiply or divide by a UnitRatio. // // The Quantity class is not well-suited to hardcore physics as it does not allow multiplying // one quantity by another. For example, multiplying meters by meters won't get you square // meters; it will get you a compiler error. It would be interesting to see if template // metaprogramming could properly deal with such things but this isn't needed for the present // use case. // // Sample usage: // // class SecondsLabel; // typedef Quantity Seconds; // constexpr Seconds SECONDS = unit(); // // class MinutesLabel; // typedef Quantity Minutes; // constexpr Minutes MINUTES = unit(); // // constexpr UnitRatio SECONDS_PER_MINUTE = // 60 * SECONDS / MINUTES; // // void waitFor(Seconds seconds) { // sleep(seconds / SECONDS); // } // void waitFor(Minutes minutes) { // waitFor(minutes * SECONDS_PER_MINUTE); // } // // void waitThreeMinutes() { // waitFor(3 * MINUTES); // } static_assert(isIntegral(), "Underlying type for Quantity must be integer."); public: inline constexpr Quantity() {} inline explicit constexpr Quantity(Number value): value(value) {} // This constructor was intended to be private, but GCC complains about it being private in a // bunch of places that don't appear to even call it, so I made it public. Oh well. template inline constexpr Quantity(const Quantity& other) : value(other.value) {} template inline constexpr Quantity operator+(const Quantity& other) const { return Quantity(value + other.value); } template inline constexpr Quantity operator-(const Quantity& other) const { return Quantity(value - other.value); } template inline constexpr Quantity operator*(OtherNumber other) const { static_assert(isIntegral(), "Multiplied Quantity by non-integer."); return Quantity(value * other); } template inline constexpr Quantity operator/(OtherNumber other) const { static_assert(isIntegral(), "Divided Quantity by non-integer."); return Quantity(value / other); } template inline constexpr decltype(Number(1) / OtherNumber(1)) operator/(const Quantity& other) const { return value / other.value; } template inline constexpr decltype(Number(1) % OtherNumber(1)) operator%(const Quantity& other) const { return value % other.value; } template inline constexpr Quantity operator*(const UnitRatio& ratio) const { return Quantity( value * ratio.unit1PerUnit2); } template inline constexpr Quantity operator/(const UnitRatio& ratio) const { return Quantity( value / ratio.unit1PerUnit2); } template inline constexpr Quantity operator%(const UnitRatio& ratio) const { return Quantity( value % ratio.unit1PerUnit2); } template inline constexpr UnitRatio operator/(const Quantity& other) const { return UnitRatio(value / other.value); } template inline constexpr bool operator==(const Quantity& other) const { return value == other.value; } template inline constexpr bool operator!=(const Quantity& other) const { return value != other.value; } template inline constexpr bool operator<=(const Quantity& other) const { return value <= other.value; } template inline constexpr bool operator>=(const Quantity& other) const { return value >= other.value; } template inline constexpr bool operator<(const Quantity& other) const { return value < other.value; } template inline constexpr bool operator>(const Quantity& other) const { return value > other.value; } template inline Quantity& operator+=(const Quantity& other) { value += other.value; return *this; } template inline Quantity& operator-=(const Quantity& other) { value -= other.value; return *this; } template inline Quantity& operator*=(OtherNumber other) { value *= other; return *this; } template inline Quantity& operator/=(OtherNumber other) { value /= other.value; return *this; } private: Number value; template friend class Quantity; template friend inline constexpr auto operator*(Number1 a, Quantity b) -> Quantity; template friend inline constexpr T unit(); }; template inline constexpr T unit() { return T(1); } // unit>() returns a Quantity of value 1. It also, intentionally, works on basic // numeric types. template inline constexpr auto operator*(Number1 a, Quantity b) -> Quantity { return Quantity(a * b.value); } template inline constexpr auto operator*(UnitRatio ratio, Quantity measure) -> decltype(measure * ratio) { return measure * ratio; } } // namespace kj #endif // KJ_UNITS_H_