-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add implementation and docs for
Constant
(#200)
This is the basic machinery for representing physical constants. Later on, we plan to include `Constant` instances in the library out of the box, but first we want to explore the feature in production inside Aurora's internal repo. The first set of basic features is to multiply and divide a wide variety of types. When we do this, the operations always take place _at compile time_, and symbolically. The next set of features is various kinds of conversions to `Quantity` types and/or raw numbers. The standout feature here is the _perfect conversion policy_: since each `Constant` fully encodes its value in the type, we know exactly which `Quantity<U, R>` instances it can convert to. Doc updates are included: I added a new reference page for `Constant`. I also updated the alternatives page. A couple libraries that were previously "good" are now "fair", because they use quantities for their constants, which is sub-optimal. mp-units moved from "best" to "good" because I think on balance we're now tied. On the one hand, they have actually included pre-defined constants. On the other hand, our core implementation is better because we also support converting to `Quantity` types. Once we include constants out of the box, I expect we'll be "best". Finally, I re-alphabetized the BUILD rules. This basically meant simply moving `//au:operators` to its rightful place; not sure how it ended up way up in the "C" section in the first place. Helps #90.
- Loading branch information
Showing
6 changed files
with
693 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Copyright 2023 Aurora Operations, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#pragma once | ||
|
||
#include "au/quantity.hh" | ||
#include "au/quantity_point.hh" | ||
#include "au/stdx/type_traits.hh" | ||
#include "au/unit_of_measure.hh" | ||
#include "au/wrapper_operations.hh" | ||
|
||
namespace au { | ||
|
||
// | ||
// A monovalue type to represent a constant value, including its units, if any. | ||
// | ||
// Users can multiply or divide `Constant` instances by raw numbers or `Quantity` instances, and it | ||
// will perform symbolic arithmetic at compile time without affecting the stored numeric value. | ||
// `Constant` also composes with other constants, and with `QuantityMaker` and other related types. | ||
// | ||
// Although `Constant` does not have any specific numeric type associated with it (as opposed to | ||
// `Quantity`), it can easily convert to any appropriate `Quantity` type, with any rep. Unlike | ||
// `Quantity`, these conversions support _exact_ safety checks, so that every conversion producing a | ||
// correctly representable value will succeed, and every unrepresentable conversion will fail. | ||
// | ||
template <typename Unit> | ||
struct Constant : detail::MakesQuantityFromNumber<Constant, Unit>, | ||
detail::ScalesQuantity<Constant, Unit>, | ||
detail::ComposesWith<Constant, Unit, Constant, Constant>, | ||
detail::ComposesWith<Constant, Unit, QuantityMaker, QuantityMaker>, | ||
detail::ComposesWith<Constant, Unit, SingularNameFor, SingularNameFor>, | ||
detail::ForbidsComposingWith<Constant, Unit, QuantityPointMaker>, | ||
detail::ForbidsComposingWith<Constant, Unit, QuantityPoint>, | ||
detail::CanScaleByMagnitude<Constant, Unit> { | ||
// Convert this constant to a Quantity of the given rep. | ||
template <typename T> | ||
constexpr auto as() const { | ||
return make_quantity<Unit>(static_cast<T>(1)); | ||
} | ||
|
||
// Convert this constant to a Quantity of the given unit and rep, ignoring safety checks. | ||
template <typename T, typename OtherUnit> | ||
constexpr auto coerce_as(OtherUnit u) const { | ||
return as<T>().coerce_as(u); | ||
} | ||
|
||
// Convert this constant to a Quantity of the given unit and rep. | ||
template <typename T, typename OtherUnit> | ||
constexpr auto as(OtherUnit u) const { | ||
static_assert(can_store_value_in<T>(u), "Cannot represent constant in this unit/rep"); | ||
return coerce_as<T>(u); | ||
} | ||
|
||
// Get the value of this constant in the given unit and rep, ignoring safety checks. | ||
template <typename T, typename OtherUnit> | ||
constexpr auto coerce_in(OtherUnit u) const { | ||
return as<T>().coerce_in(u); | ||
} | ||
|
||
// Get the value of this constant in the given unit and rep. | ||
template <typename T, typename OtherUnit> | ||
constexpr auto in(OtherUnit u) const { | ||
static_assert(can_store_value_in<T>(u), "Cannot represent constant in this unit/rep"); | ||
return coerce_in<T>(u); | ||
} | ||
|
||
// Implicitly convert to any quantity type which passes safety checks. | ||
template <typename U, typename R> | ||
constexpr operator Quantity<U, R>() const { | ||
return as<R>(U{}); | ||
} | ||
|
||
// Static function to check whether this constant can be exactly-represented in the given rep | ||
// `T` and unit `OtherUnit`. | ||
template <typename T, typename OtherUnit> | ||
static constexpr bool can_store_value_in(OtherUnit other) { | ||
return representable_in<T>(unit_ratio(Unit{}, other)); | ||
} | ||
}; | ||
|
||
// Make a constant from the given unit. | ||
// | ||
// Note that the argument is a _unit slot_, and thus can also accept things like `QuantityMaker` and | ||
// `SymbolFor` in addition to regular units. | ||
template <typename UnitSlot> | ||
constexpr Constant<AssociatedUnitT<UnitSlot>> make_constant(UnitSlot) { | ||
return {}; | ||
} | ||
|
||
// Support using `Constant` in a unit slot. | ||
template <typename Unit> | ||
struct AssociatedUnit<Constant<Unit>> : stdx::type_identity<Unit> {}; | ||
|
||
} // namespace au |
Oops, something went wrong.