Merge branch 'new_design'

This commit is contained in:
Mateusz Pusz
2019-12-17 09:21:11 +01:00
121 changed files with 6375 additions and 3956 deletions

View File

@@ -25,15 +25,15 @@ AccessModifierOffset: -2
# AlwaysBreakTemplateDeclarations: Yes
# BinPackArguments: true
# BinPackParameters: true
# BraceWrapping:
BraceWrapping:
# AfterCaseLabel: false
# AfterClass: false
AfterClass: false
# AfterControlStatement: false
# AfterEnum: false
# AfterFunction: false
AfterFunction: true
# AfterNamespace: false
# AfterObjCDeclaration: false
# AfterStruct: false
AfterStruct: false
# AfterUnion: false
# AfterExternBlock: false
# BeforeCatch: false
@@ -44,9 +44,9 @@ AccessModifierOffset: -2
# SplitEmptyNamespace: true
# BreakAfterJavaFieldAnnotations: false
# BreakBeforeBinaryOperators: None
BreakBeforeBraces: Stroustrup
BreakBeforeBraces: Custom
# BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
# BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakConstructorInitializersBeforeComma: true
BreakInheritanceList: AfterColon
@@ -66,6 +66,7 @@ ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
- SECTION
- GIVEN
- WHEN
- THEN
@@ -93,7 +94,7 @@ IncludeCategories:
# MacroBlockBegin: ''
# MacroBlockEnd: ''
# MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
# NamespaceIndentation: None
# ObjCBinPackProtocolList: Never
# ObjCBlockIndentWidth: 2
# ObjCSpaceAfterProperty: false
@@ -143,9 +144,9 @@ NamespaceIndentation: All
SpaceAfterTemplateKeyword: false
# SpaceBeforeAssignmentOperators: true
# SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: false
# SpaceBeforeCtorInitializerColon: true
# SpaceBeforeInheritanceColon: true
SpaceBeforeParens: Never
# SpaceBeforeParens: ControlStatements
# SpaceBeforeRangeBasedForLoopColon: true
# SpaceInEmptyBlock: false
# SpaceInEmptyParentheses: false

13
.gitattributes vendored
View File

@@ -1,3 +1,16 @@
# Set the default behavior
* text=auto eol=lf
*.{cmd,[cC][mM][dD]} text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf
# Explicitly declare text files to always be normalized and converted to native line endings on checkout
*.cpp text
*.h text
*.py text
*.txt text
*.md text
*.yml text
# Denote all files that are truly binary and should not be modified
*.png binary
*.jpg binary

149
README.md
View File

@@ -5,9 +5,32 @@
# `mp-units` - A Units Library for C++
## TL;DR
```cpp
constexpr Velocity auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}
int main()
{
using namespace si::literals;
Velocity auto v1 = avg_speed(220km, 2h);
Velocity auto v2 = avg_speed(140mi, 2h);
std::cout << v1 << '\n'; // 110 km/h
std::cout << quantity_cast<si::metre_per_second>(speed) << '\n'; // 30.5556 m/s
std::cout << v2 << '\n'; // 70 mi/h
}
```
Try it on [Compiler Explorer](https://godbolt.org/z/OVpkT1).
## Summary
`Units` is a compile-time enabled Modern C++ library that provides compile-time dimensional
`mp-units` is a compile-time enabled Modern C++ library that provides compile-time dimensional
analysis and unit/quantity manipulation. The basic idea and design heavily bases on
`std::chrono::duration` and extends it to work properly with many dimensions.
@@ -31,74 +54,120 @@ static_assert(1000 / 1s == 1kHz);
static_assert(10km / 5km == 2);
```
## Usage Overview
The library framework consists of a few concepts: quantities, units, dimensions and their exponents. From the user's
point of view the most important is a `quantity`.
## Getting Started
Quantity is a concrete amount of a unit for a specified dimension with a specific representation:
The library framework consists of a few concepts: quantities, units, dimensions and their
exponents. From the user's point of view the most important is a `quantity`.
A quantity is a concrete amount of a unit for a specified dimension with a specific representation:
```cpp
units::quantity<units::kilometre, double> d1(123);
auto d2 = 123km; // units::quantity<units::kilometre, std::int64_t>
units::quantity<units::si::dim_length, units::si::kilometre, double> d(123);
```
There are C++ concepts provided for each such quantity type:
To simplify quantity creation the library provides helper aliases for quantities of different
dimensions. Thanks to then the above example can be rewritten as follows:
```cpp
template<typename T>
concept Length = QuantityOf<T, length>;
units::si::length<units::si::kilometre, double> d(123);
```
With that we can easily write a function template like this:
To simplify creations of compile-time known constants the library provides UDLs for each unit.
Thanks to them the same code can be as simple as:
```cpp
constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t)
using namespace units::si::literals;
auto d = 123km; // units::length<units::si::kilometre, std::int64_t>
```
For brevity, the next examples will assume:
```cpp
using namespace units;
```
Let's assume that the user wants to write the following code:
```cpp
int main()
{
using namespace si::literals;
auto v1 = avg_speed(220km, 2h);
auto v2 = avg_speed(140mi, 2h);
// ...
}
```
`avg_speed` is a simple function calculating an average speed from a distance and duration. It can
be implemented as:
```cpp
constexpr si::velocity<si::metre_per_second, int> avg_speed(si::length<si::metre> d, si::time<si::second> t)
{
return d / t;
}
```
Concepts usage in the function above guarantee correctness enforced in compile-time and the
guarantee that no unneeded intermediate conversions will ever be applied no matter which
units the user will decide to pass to such function template:
However, this function will perform unnecessary intermediate conversions (from kilometers to meters,
from hours to seconds, and from meters per second to kilometers per hour). To eliminate all that
overhead we have to write a template function:
```cpp
using namespace units;
constexpr quantity<kilometre> distance(220);
constexpr quantity<hour> time(2);
constexpr Velocity speed = avg_speed(distance, time);
static_assert(std::same_as<std::remove_cvref_t<decltype(speed)>, quantity<kilometre_per_hour>>);
static_assert(speed.count() == 110);
template<typename U1, typename R1, typename U2, typename R2>
constexpr auto avg_speed(si::length<U1, R1> d, si::time<U2, R2> t)
{
return d / t;
}
```
The units library also tries really hard to printing any quantity in the most user friendly fashion:
This function will work for every SI unit and representation without any unnecessary overhead.
It is also simple enough to ensure that the returned type is actually a velocity. However,
it might not always be the case. For more complicated calculations we would like to ensure
that we are returning a correct type and also inform the user of that fact in the function
template interface. Also we might want to implement a truly generic function that will work
efficiently not only with SI units but also with other systems of units like CGS. The solution
to this are C++20 concepts and generic functions.
```cpp
std::cout << speed << '\n';
std::cout << quantity_cast<metre_per_second>(speed) << '\n';
std::cout << avg_speed(140.mi, 2h) << '\n';
constexpr Velocity auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}
```
Try it on [Compiler Explorer](https://godbolt.org/z/OVpkT1).
The units library also tries really hard to print any quantity in the most user friendly
fashion:
```cpp
int main()
{
using namespace si::literals;
Velocity auto v1 = avg_speed(220km, 2h);
Velocity auto v2 = avg_speed(140mi, 2h);
std::cout << v1 << '\n'; // 110 km/h
std::cout << quantity_cast<si::metre_per_second>(speed) << '\n'; // 30.5556 m/s
std::cout << v2 << '\n'; // 70 mi/h
}
```
## Library design
`mp-units` library design rationale and documentation can be found in [doc/DESIGN.md](doc/DESIGN.md)
A detailed `mp-units` library design rationale and documentation can be found in
[doc/DESIGN.md](doc/DESIGN.md)
## Repository structure
That repository contains the following independent `cmake`-based projects:
- `./src` - header-only project for `units`
- `.` - project used for development needs that wraps `./src` project together with
usage examples and unit tests
- `./test_package` - library installation and Conan package verification
This repository contains three independent `cmake`-based projects:
1. `./src` - header-only project containing whole `mp-units` library
2. `.` - project used as an entry point for library development (it wraps `./src` project
together with usage examples and tests)
3. `./test_package` - library installation and Conan package verification
Please note that the projects depend on `cmake` git submodule in the `./cmake/common`
NOTE: Please note that this repository depends on a git submodule in the `./cmake/common`
subdirectory.
@@ -112,6 +181,16 @@ NOTE: This library as of now compiles correctly only with gcc-9.1 and newer.
## Release notes
- 0.5.0 ???
- Major refactoring and rewrite of the library
- Units are now independent from dimensions
- Dimensions are now depended on units (base or coherent units are provided in a class template)
- Quantity gets a Dimension template parameter again (as unit does not provide information about
its dimension anymore)
- Added official CGS system support
- Added official data information system support
- Repository file tree cleanup
- 0.4.0 Nov 17, 2019
- Support for derived dimensions in `exp` added
- Added `pow()` and `sqrt()` operations on quantities

View File

@@ -47,9 +47,10 @@ class UnitsConan(ConanFile):
exports_sources = ["src/*", "test/*", "cmake/*", "example/*","CMakeLists.txt"]
settings = "os", "compiler", "build_type", "arch"
requires = (
"range-v3/0.9.1@ericniebler/stable",
"Catch2/2.10.0@catchorg/stable",
"fmt/6.0.0"
"fmt/6.1.0"
)
build_requires = (
"Catch2/2.11.0@catchorg/stable"
)
generators = "cmake"
@@ -73,6 +74,10 @@ class UnitsConan(ConanFile):
cmake.configure(source_folder="src", build_folder="src")
return cmake
def requirements(self):
if Version(self.settings.compiler.version) < "10":
self.requires("range-v3/0.10.0@ericniebler/stable")
def build(self):
cmake = self._configure_cmake()
cmake.build()
@@ -91,8 +96,7 @@ class UnitsConan(ConanFile):
"-fconcepts",
"-Wno-literal-suffix",
"-Wno-non-template-friend",
"-Wno-stringop-overflow",
"-Wno-pedantic"
"-Wno-stringop-overflow"
]
def package_id(self):

File diff suppressed because it is too large Load Diff

View File

@@ -39,18 +39,18 @@ steps may be done:
```
- add `units` as a dependency to your `conan` file. For example to use testing version of
`0.4.0` of `mp-units` add:
`0.5.0` of `mp-units` add:
- `conanfile.txt`
```text
[requires]
mp-units/0.4.0@mpusz/testing
mp-units/0.5.0@mpusz/testing
```
- `conanfile.py`
```python
requires = "mp-units/0.4.0@mpusz/testing"
requires = "mp-units/0.5.0@mpusz/testing"
```
- link your `cmake` target with units
@@ -93,5 +93,5 @@ conan create . <username>/<channel> -s cppstd=20 -b=outdated <your_profile_and_s
## Upload package to conan server
```shell
conan upload -r <remote-name> --all mp-units/0.4.0@<user>/<channel>
conan upload -r <remote-name> --all mp-units/0.5.0@<user>/<channel>
```

BIN
doc/design.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 32 KiB

46
doc/nomnoml.md Normal file
View File

@@ -0,0 +1,46 @@
# nomnoml
Graphs in the documentation are created with <http://www.nomnoml.com>.
## Concepts
```text
[<abstract>Dimension|
[base_dimension<Symbol, Unit>]<-[exp<Dimension, Num, Den>]
[derived_dimension<Child, Unit, Exponent...>]<-[exp<Dimension, Num, Den>]
[exp<Dimension, Num, Den>]<-[derived_dimension<Child, Unit, Exponent...>]
]
[<abstract>Quantity|
[quantity<Dimension, Unit, Rep>]
]
[<abstract>Unit]<-[Dimension]
[Dimension]<-[Quantity]
[Unit]<-[Quantity]
```
## Units
```text
#direction: right
[scaled_unit<Ratio, Unit>]<:-[unit<Child>]
[scaled_unit<Ratio, Unit>]<:-[named_unit<Child, Symbol, PrefixType>]
[scaled_unit<Ratio, Unit>]<:-[named_scaled_unit<Child, Symbol, PrefixType, Ratio, Unit>]
[scaled_unit<Ratio, Unit>]<:-[prefixed_unit<Child, Prefix, Unit>]
[scaled_unit<Ratio, Unit>]<:-[deduced_unit<Child, Dimension, Unit, Unit...>]
```
## Downcasting 1
```text
[detail::derived_dimension_base<exp<si::dim_length, 2>>]<:-[dim_area]
```
## Downcasting 2
```text
[downcast_base<detail::derived_dimension_base<exp<si::dim_length, 2>>>]<:-[detail::derived_dimension_base<exp<si::dim_length, 2>>]
[detail::derived_dimension_base<exp<si::dim_length, 2>>]<:-[downcast_child<dim_area, detail::derived_dimension_base<exp<si::dim_length, 2>>>]
[downcast_child<dim_area, detail::derived_dimension_base<exp<si::dim_length, 2>>>]<:-[dim_area]```

BIN
doc/units.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -20,15 +20,11 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# example app
add_executable(example example.cpp)
target_link_libraries(example
PRIVATE
mp::units
)
function(add_example target)
add_executable(${target} ${target}.cpp)
target_link_libraries(${target} PRIVATE mp::units)
endfunction()
add_executable(measurement measurement.cpp)
target_link_libraries(measurement
PRIVATE
mp::units
)
add_example(avg_velocity)
add_example(measurement)
add_example(unknown_dimension)

186
example/avg_velocity.cpp Normal file
View File

@@ -0,0 +1,186 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <units/physical/si/velocity.h>
#include <units/physical/cgs/velocity.h>
#include <iostream>
namespace {
constexpr units::si::velocity<units::si::metre_per_second, int>
fixed_int_si_avg_speed(units::si::length<units::si::metre, int> d,
units::si::time<units::si::second, int> t)
{
return d / t;
}
constexpr units::si::velocity<units::si::metre_per_second>
fixed_double_si_avg_speed(units::si::length<units::si::metre> d,
units::si::time<units::si::second> t)
{
return d / t;
}
template<typename U1, typename R1, typename U2, typename R2>
constexpr units::Velocity AUTO si_avg_speed(units::si::length<U1, R1> d,
units::si::time<U2, R2> t)
{
return d / t;
}
constexpr units::Velocity AUTO avg_speed(units::Length AUTO d, units::Time AUTO t)
{
return d / t;
}
template<units::Length D, units::Time T, units::Velocity V>
void print_result(D distance, T duration, V velocity)
{
const auto result_in_kmph = units::quantity_cast<units::si::velocity<units::si::kilometre_per_hour>>(velocity);
std::cout << "Average speed of a car that makes " << distance << " in "
<< duration << " is " << result_in_kmph << ".\n";
}
void example()
{
using namespace units;
// SI (int)
{
using namespace units::si::literals;
constexpr Length AUTO distance = 220km; // constructed from a UDL
constexpr si::time<si::hour, int> duration(2); // constructed from a value
std::cout << "SI units with 'int' as representation\n";
print_result(distance, duration, fixed_int_si_avg_speed(distance, duration));
print_result(distance, duration, fixed_double_si_avg_speed(distance, duration));
print_result(distance, duration, si_avg_speed(distance, duration));
print_result(distance, duration, avg_speed(distance, duration));
}
// SI (double)
{
using namespace units::si::literals;
constexpr Length AUTO distance = 220.km; // constructed from a UDL
constexpr si::time<si::hour> duration(2); // constructed from a value
std::cout << "\nSI units with 'double' as representation\n";
// conversion from a floating-point to an integral type is a truncating one so an explicit cast is needed
print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast<int>(distance), quantity_cast<int>(duration)));
print_result(distance, duration, fixed_double_si_avg_speed(distance, duration));
print_result(distance, duration, si_avg_speed(distance, duration));
print_result(distance, duration, avg_speed(distance, duration));
}
// Customary Units (int)
{
using namespace units::si::literals;
constexpr Length AUTO distance = 140mi; // constructed from a UDL
constexpr si::time<si::hour, int> duration(2); // constructed from a value
std::cout << "\nUS Customary Units with 'int' as representation\n";
// it is not possible to make a lossless conversion of miles to meters on an integral type
// (explicit cast needed)
print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast<si::metre>(distance), duration));
print_result(distance, duration, fixed_double_si_avg_speed(distance, duration));
print_result(distance, duration, si_avg_speed(distance, duration));
print_result(distance, duration, avg_speed(distance, duration));
}
// Customary Units (double)
{
using namespace units::si::literals;
constexpr Length AUTO distance = 140.mi; // constructed from a UDL
constexpr si::time<si::hour> duration(2); // constructed from a value
std::cout << "\nUS Customary Units with 'double' as representation\n";
// conversion from a floating-point to an integral type is a truncating one so an explicit cast is needed
// also it is not possible to make a lossless conversion of miles to meters on an integral type
// (explicit cast needed)
print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast<si::length<si::metre, int>>(distance), quantity_cast<int>(duration)));
print_result(distance, duration, fixed_double_si_avg_speed(distance, duration));
print_result(distance, duration, si_avg_speed(distance, duration));
print_result(distance, duration, avg_speed(distance, duration));
}
// CGS (int)
{
using namespace units::cgs::literals;
constexpr Length AUTO distance = 22'000'000cm; // constructed from a UDL
constexpr cgs::time<si::hour, int> duration(2); // constructed from a value
std::cout << "\nCGS units with 'int' as representation\n";
// it is not possible to make a lossless conversion of centimeters to meters on an integral type
// (explicit cast needed)
print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast<si::metre>(distance), duration));
print_result(distance, duration, fixed_double_si_avg_speed(distance, duration));
// not possible to convert both a dimension and a unit with implicit cast
print_result(distance, duration, si_avg_speed(quantity_cast<si::dim_length>(distance), duration));
print_result(distance, duration, avg_speed(distance, duration));
}
// CGS (double)
{
using namespace units::cgs::literals;
constexpr Length AUTO distance = 22'000'000.cm; // constructed from a UDL
constexpr cgs::time<si::hour> duration(2); // constructed from a value
std::cout << "\nCGS units with 'double' as representation\n";
// conversion from a floating-point to an integral type is a truncating one so an explicit cast is needed
// it is not possible to make a lossless conversion of centimeters to meters on an integral type
// (explicit cast needed)
print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast<si::length<si::metre, int>>(distance), quantity_cast<int>(duration)));
print_result(distance, duration, fixed_double_si_avg_speed(distance, duration));
// not possible to convert both a dimension and a unit with implicit cast
print_result(distance, duration, si_avg_speed(quantity_cast<si::dim_length>(distance), duration));
print_result(distance, duration, avg_speed(distance, duration));
}
}
} // namespace
int main()
{
try {
example();
}
catch (const std::exception& ex) {
std::cerr << "Unhandled std exception caught: " << ex.what() << '\n';
}
catch (...) {
std::cerr << "Unhandled unknown exception caught\n";
}
}

View File

@@ -20,122 +20,142 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <units/dimensions/acceleration.h>
#include <units/physical/si/acceleration.h>
#include <cmath>
#include <iostream>
namespace {
template<typename T, template<typename> typename Trait>
concept Satisfies = Trait<T>::value;
// root sum of squares
template<typename T>
T rss(const T& v1, const T& v2)
{
return std::sqrt(std::pow(v1, 2) + std::pow(v2, 2));
}
// root sum of squares
template<typename T>
T rss(const T& v1, const T& v2)
template<class T>
class measurement {
public:
using value_type = T;
measurement() = default;
constexpr /* explicit */ measurement(const value_type& val, const value_type& err = {}) :
// cannot be explicit as `magma` concept requires implicit conversions :-(
value_(val),
uncertainty_(std::abs(err))
{
return std::sqrt(std::pow(v1, 2) + std::pow(v2, 2));
}
template<class T>
class measurement {
public:
using value_type = T;
constexpr const value_type& value() const { return value_; }
constexpr const value_type& uncertainty() const { return uncertainty_; }
measurement() = default;
constexpr value_type relative_uncertainty() const { return uncertainty() / value(); }
constexpr value_type lower_bound() const { return value() - uncertainty(); }
constexpr value_type upper_bound() const { return value() + uncertainty(); }
constexpr /* explicit */ measurement(const value_type& val, const value_type& err = {}): // cannot be explicit as `magma` concept requires implicit conversions :-(
value_(val), uncertainty_(std::abs(err))
{
}
[[nodiscard]] constexpr measurement operator-() const { return measurement(-value(), uncertainty()); }
constexpr const value_type& value() const { return value_; }
constexpr const value_type& uncertainty() const { return uncertainty_; }
[[nodiscard]] friend constexpr measurement operator+(const measurement& lhs, const measurement& rhs)
{
return measurement(lhs.value() + rhs.value(), rss(lhs.uncertainty(), rhs.uncertainty()));
}
constexpr value_type relative_uncertainty() const { return uncertainty() / value(); }
constexpr value_type lower_bound() const { return value() - uncertainty(); }
constexpr value_type upper_bound() const { return value() + uncertainty(); }
[[nodiscard]] friend constexpr measurement operator-(const measurement& lhs, const measurement& rhs)
{
return measurement(lhs.value() - rhs.value(), rss(lhs.uncertainty(), rhs.uncertainty()));
}
[[nodiscard]] constexpr measurement operator-() const { return measurement(-value(), uncertainty()); }
[[nodiscard]] friend constexpr measurement operator*(const measurement& lhs, const measurement& rhs)
{
const auto val = lhs.value() * rhs.value();
return measurement(val, val * rss(lhs.relative_uncertainty(), rhs.relative_uncertainty()));
}
[[nodiscard]] friend constexpr measurement operator+(const measurement& lhs, const measurement& rhs)
{
return measurement(lhs.value() + rhs.value(), rss(lhs.uncertainty(), rhs.uncertainty()));
}
[[nodiscard]] friend constexpr measurement operator/(const measurement& lhs, const measurement& rhs)
{
const auto val = lhs.value() / rhs.value();
return measurement(val, val * rss(lhs.relative_uncertainty(), rhs.relative_uncertainty()));
}
[[nodiscard]] friend constexpr measurement operator-(const measurement& lhs, const measurement& rhs)
{
return measurement(lhs.value() - rhs.value(), rss(lhs.uncertainty(), rhs.uncertainty()));
}
#if __GNUC__ >= 10
[[nodiscard]] friend constexpr measurement operator*(const measurement& lhs, const measurement& rhs)
{
const auto val = lhs.value() * rhs.value();
return measurement(val, val * rss(lhs.relative_uncertainty(), rhs.relative_uncertainty()));
}
[[nodiscard]] friend constexpr auto operator<=>(const measurement& lhs, const measurement& rhs) = default;
[[nodiscard]] friend constexpr bool operator==(const measurement& lhs, const measurement& rhs) = default;
[[nodiscard]] friend constexpr measurement operator/(const measurement& lhs, const measurement& rhs)
{
const auto val = lhs.value() / rhs.value();
return measurement(val, val * rss(lhs.relative_uncertainty(), rhs.relative_uncertainty()));
}
#else
[[nodiscard]] friend constexpr bool operator==(const measurement& lhs, const measurement& rhs)
{
return lhs.value() == rhs.value() && lhs.uncertainty() == rhs.uncertainty();
}
[[nodiscard]] friend constexpr bool operator==(const measurement& lhs, const measurement& rhs)
{
return lhs.value() == rhs.value() && lhs.uncertainty() == rhs.uncertainty();
}
[[nodiscard]] friend constexpr bool operator!=(const measurement& lhs, const measurement& rhs)
{
return !(lhs == rhs);
}
[[nodiscard]] friend constexpr bool operator!=(const measurement& lhs, const measurement& rhs)
{
return !(lhs == rhs);
}
[[nodiscard]] friend constexpr bool operator<(const measurement& lhs, const measurement& rhs)
{
return lhs.value() == rhs.value() ? lhs.uncertainty() < rhs.uncertainty() : lhs.value() < rhs.value();
}
[[nodiscard]] friend constexpr bool operator<(const measurement& lhs, const measurement& rhs)
{
return lhs.value() == rhs.value() ? lhs.uncertainty() < rhs.uncertainty() : lhs.value() < rhs.value();
}
[[nodiscard]] friend constexpr bool operator>(const measurement& lhs, const measurement& rhs)
{
return rhs < lhs;
}
[[nodiscard]] friend constexpr bool operator>(const measurement& lhs, const measurement& rhs) { return rhs < lhs; }
[[nodiscard]] friend constexpr bool operator<=(const measurement& lhs, const measurement& rhs)
{
return !(rhs < lhs);
}
[[nodiscard]] friend constexpr bool operator<=(const measurement& lhs, const measurement& rhs)
{
return !(rhs < lhs);
}
[[nodiscard]] friend constexpr bool operator>=(const measurement& lhs, const measurement& rhs)
{
return !(lhs < rhs);
}
[[nodiscard]] friend constexpr bool operator>=(const measurement& lhs, const measurement& rhs)
{
return !(lhs < rhs);
}
friend std::ostream& operator<<(std::ostream& os, const measurement& v)
{
return os << v.value() << " ± " << v.uncertainty();
}
#endif
private:
value_type value_{};
value_type uncertainty_{};
};
friend std::ostream& operator<<(std::ostream& os, const measurement& v)
{
return os << v.value() << " ± " << v.uncertainty();
}
template<units::Unit U>
using m_quantity = units::quantity<U, measurement<double>>;
private:
value_type value_{};
value_type uncertainty_{};
};
static_assert(units::Scalar<measurement<double>>);
} // namespace
template<typename T>
inline constexpr bool units::treat_as_floating_point<measurement<T>> = std::is_floating_point_v<T>;
namespace {
void example()
{
using namespace units;
const auto a = si::acceleration<si::metre_per_second_sq, measurement<double>>(measurement(9.8, 0.1));
const auto t = si::time<si::second, measurement<double>>(measurement(1.2, 0.1));
const Velocity AUTO v1 = a * t;
std::cout << a << " * " << t << " = " << v1 << " = " << quantity_cast<si::kilometre_per_hour>(v1) << '\n';
si::length<si::metre, measurement<double>> length(measurement(123., 1.));
std::cout << "10 * " << length << " = " << 10 * length << '\n';
}
} // namespace
int main()
{
const auto a = m_quantity<units::metre_per_second_sq>(measurement(9.8, 0.1));
const auto t = m_quantity<units::second>(measurement(1.2, 0.1));
units::Velocity AUTO v1 = a * t;
m_quantity<units::kilometre_per_hour> v2(v1);
std::cout << a << " * " << t << " = " << v1 << " = " << v2 << '\n';
m_quantity<units::metre> length(measurement(123., 1.));
std::cout << "10 * " << length << " = " << 10 * length << '\n';
try {
example();
} catch (const std::exception& ex) {
std::cerr << "Unhandled std exception caught: " << ex.what() << '\n';
} catch (...) {
std::cerr << "Unhandled unknown exception caught\n";
}
}

View File

@@ -20,43 +20,43 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <units/dimensions/velocity.h>
#include <units/physical/si/velocity.h>
#include <iostream>
namespace {
using namespace units::literals;
template<units::Length D, units::Time T>
constexpr units::Velocity AUTO avg_speed(D d, T t)
{
return d / t;
}
template<units::Velocity V, units::Time T>
void example_1(V v, T t)
void example()
{
const units::Length AUTO distance = v * t;
std::cout << "A car driving " << v << " in a time of " << t << " will pass "
<< units::quantity_cast<units::quantity<units::metre, double>>(distance) << ".\n";
using namespace units::si::literals;
units::Length AUTO d1 = 123m;
units::Time AUTO t1 = 10s;
units::Velocity AUTO v1 = avg_speed(d1, t1);
auto temp1 = v1 * 50m; // produces intermediate unknown dimension with 'unknown_unit' as its 'coherent_unit'
units::Velocity AUTO v2 = temp1 / 100m; // back to known dimensions again
units::Length AUTO d2 = v2 * 60s;
std::cout << "d1 = " << d1 << '\n';
std::cout << "t1 = " << t1 << '\n';
std::cout << "v1 = " << v1 << '\n';
std::cout << "temp1 = " << temp1 << '\n';
std::cout << "v2 = " << v2 << '\n';
std::cout << "d2 = " << d2 << '\n';
}
void example_2(double distance_v, double duration_v)
{
units::quantity<units::kilometre> distance(distance_v);
units::quantity<units::hour> duration(duration_v);
const auto kmph = quantity_cast<units::kilometre_per_hour>(avg_speed(distance, duration));
std::cout << "Average speed of a car that makes " << distance << " in "
<< duration << " is " << kmph << ".\n";
}
}
} // namespace
int main()
{
try {
example_1(60kmph, 10.0min);
example_2(220, 2);
example();
}
catch (const std::exception& ex) {
std::cerr << "Unhandled std exception caught: " << ex.what() << '\n';

View File

@@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 3.8)
#cmake_policy(SET CMP0076 NEW)
project(units
VERSION 0.4.0
VERSION 0.5.0
LANGUAGES CXX
)
@@ -53,7 +53,6 @@ add_library(units INTERFACE)
target_compile_features(units INTERFACE cxx_std_20)
target_link_libraries(units
INTERFACE
CONAN_PKG::range-v3
CONAN_PKG::fmt
)
target_include_directories(units
@@ -67,10 +66,13 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
-Wno-literal-suffix
-Wno-non-template-friend
-Wno-stringop-overflow
# TODO gcc:92101
-Wno-pedantic
)
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0)
target_link_libraries(units
INTERFACE
CONAN_PKG::range-v3
)
target_compile_options(units
INTERFACE
-fconcepts

View File

@@ -0,0 +1,66 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/bits/external/fixed_string.h>
#include <units/concepts.h>
#include <type_traits>
namespace units {
/**
* @brief A dimension of a base quantity
*
* Base quantity is a quantity in a conventionally chosen subset of a given system of quantities, where no quantity
* in the subset can be expressed in terms of the other quantities within that subset. They are referred to as
* being mutually independent since a base quantity cannot be expressed as a product of powers of the other base
* quantities.
*
* Base unit is a measurement unit that is adopted by convention for a base quantity in a specific system of units.
*
* Pair of Symbol and Unit template parameters form an unique identifier of the base dimension. The same identifiers can
* be multiplied and divided which will result with an adjustment of its factor in an Exponent of a DerivedDimension
* (in case of zero the dimension will be simplified and removed from further analysis of current expresion). In case
* the Symbol is the same but the Unit differs (i.e. mixing SI and CGS length), there is no automatic simplification but
* is possible to force it with a quantity_cast.
*
* @tparam Symbol an unique identifier of the base dimension used to provide dimensional analysis support
* @tparam U a base unit to be used for this base dimension
*/
template<basic_fixed_string Symbol, Unit U>
requires U::is_named
struct base_dimension {
using base_type_workaround = base_dimension; // TODO Replace with is_derived_from_instantiation when fixed
static constexpr auto symbol = Symbol;
using base_unit = U;
};
// base_dimension_less
// TODO Remove the below when https://bugs.llvm.org/show_bug.cgi?id=32208 is fixed
// clang-format off
template<BaseDimension D1, BaseDimension D2>
struct base_dimension_less : std::bool_constant<
D1::symbol < D2::symbol || (D1::symbol == D2::symbol && D1::base_unit::symbol < D1::base_unit::symbol)> {};
// clang-format on
} // namespace units

View File

@@ -22,32 +22,39 @@
#pragma once
#include <units/bits/hacks.h>
#include <units/bits/numeric_concepts.h>
#include <units/bits/customization_points.h>
#include <units/base_dimension.h>
#include <units/exp.h>
#include <units/ratio.h>
namespace units {
namespace units::detail {
namespace detail {
template<Exponent E>
requires (E::den == 1 || E::den == 2) // TODO provide support for any den
struct exp_ratio {
using base_ratio = E::dimension::base_unit::ratio;
using positive_ratio = conditional<E::num * E::den < 0, ratio<base_ratio::den, base_ratio::num>, base_ratio>;
static constexpr std::int64_t N = E::num * E::den < 0 ? -E::num : E::num;
using pow = ratio_pow<positive_ratio, N>;
using type = conditional<E::den == 2, ratio_sqrt<pow>, pow>;
};
template<typename T, typename U = T>
concept basic_arithmetic = // exposition only
std::magma<std::ranges::plus, T, U> &&
std::magma<std::ranges::minus, T, U> &&
std::magma<std::ranges::times, T, U> &&
std::magma<std::ranges::divided_by, T, U>;
template<typename ExpList>
struct base_units_ratio_impl;
template<typename From, typename To>
concept safe_convertible = // exposition only
std::convertible_to<From, To> &&
(treat_as_floating_point<To> || (!treat_as_floating_point<From>));
template<typename E, typename... Es>
struct base_units_ratio_impl<exp_list<E, Es...>> {
using type = ratio_multiply<typename exp_ratio<E>::type, typename base_units_ratio_impl<exp_list<Es...>>::type>;
};
template<typename Rep, typename unit_from, typename unit_to>
concept safe_divisible = // exposition only
treat_as_floating_point<Rep> ||
ratio_divide<typename unit_from::ratio, typename unit_to::ratio>::den == 1;
template<typename E>
struct base_units_ratio_impl<exp_list<E>> {
using type = exp_ratio<E>::type;
};
}
/**
* @brief Calculates the common ratio of all the references of base units in the derived dimension
*/
template<typename D>
using base_units_ratio = base_units_ratio_impl<typename D::exponents>::type;
} // namespace units
} // namespace units::detail

View File

@@ -0,0 +1,66 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/bits/dimension_op.h>
namespace units {
template<Dimension D, UnitOf<D> U, Scalar Rep>
class quantity;
namespace detail {
template<typename Q1, typename Q2, typename Rep>
struct common_quantity_impl;
template<typename D, typename U, typename Rep1, typename Rep2, typename Rep>
struct common_quantity_impl<quantity<D, U, Rep1>, quantity<D, U, Rep2>, Rep> {
using type = quantity<D, U, Rep>;
};
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2, typename Rep>
struct common_quantity_impl<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, Rep> {
using type = quantity<D, downcast_unit<D, common_ratio<typename U1::ratio, typename U2::ratio>>, Rep>;
};
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2, typename Rep>
requires same_unit_reference<dimension_unit<D1>, dimension_unit<D2>>::value
struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep> {
using type = quantity<D1, downcast_unit<D1, common_ratio<typename U1::ratio, typename U2::ratio>>, Rep>;
};
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2, typename Rep>
struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep> {
using ratio1 = ratio_multiply<typename D1::base_units_ratio, typename U1::ratio>;
using ratio2 = ratio_multiply<typename D2::base_units_ratio, typename U2::ratio>;
using type = quantity<D1, downcast_unit<D1, common_ratio<ratio1, ratio2>>, Rep>;
};
} // namespace detail
template<Quantity Q1, Quantity Q2, Scalar Rep = std::common_type_t<typename Q1::rep, typename Q2::rep>>
requires equivalent_dim<typename Q1::dimension, typename Q2::dimension>
using common_quantity = detail::common_quantity_impl<Q1, Q2, Rep>::type;
} // namespace units

View File

@@ -1,115 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <type_traits>
#include <cmath>
namespace units {
// treat_as_floating_point
template<typename Rep> // TODO Conceptify that
inline constexpr bool treat_as_floating_point = std::is_floating_point_v<Rep>;
// isnan
namespace isnan_impl {
// non-ADL lookup block
void isnan(); // undefined
template<typename>
inline constexpr bool has_customization = false;
template<typename T>
requires requires(const T& t) {
{ isnan(t) } -> bool;
}
inline constexpr bool has_customization<T> = true;
struct fn {
template<typename T>
constexpr bool operator()(const T&) const
{
return false;
}
template<typename T>
requires treat_as_floating_point<T>
constexpr bool operator()(const T& value) const
{
return std::isnan(value);
}
template<typename T>
requires treat_as_floating_point<T> && has_customization<T>
constexpr bool operator()(const T& value) const
{
return isnan(value); // uses ADL
}
};
}
inline constexpr isnan_impl::fn isnan{};
// isfinite
namespace isfinite_impl {
// non-ADL lookup block
void isfinite(); // undefined
template<typename>
inline constexpr bool has_customization = false;
template<typename T>
requires requires(const T& t) {
{ isfinite(t) } -> bool;
}
inline constexpr bool has_customization<T> = true;
struct fn {
template<typename T>
constexpr bool operator()(const T&) const
{
return true;
}
template<typename T>
requires treat_as_floating_point<T>
constexpr bool operator()(const T& value) const
{
return std::isfinite(value);
}
template<typename T>
requires treat_as_floating_point<T> && has_customization<T>
constexpr bool operator()(const T& value) const
{
return isfinite(value); // uses ADL
}
};
}
inline constexpr isfinite_impl::fn isfinite{};
}

View File

@@ -0,0 +1,82 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/bits/external/fixed_string.h>
#include <units/bits/external/text_tools.h>
#include <units/derived_dimension.h>
namespace units::detail {
template<bool Divide, std::size_t Idx>
constexpr auto operator_text()
{
if constexpr(Idx == 0) {
if constexpr(Divide) {
return basic_fixed_string("1/");
}
else {
return basic_fixed_string("");
}
}
else {
if constexpr(Divide) {
return basic_fixed_string("/");
}
else {
return basic_fixed_string("");
}
}
}
template<typename E, basic_fixed_string Symbol, std::size_t Idx>
constexpr auto exp_text()
{
// get calculation operator + symbol
const auto txt = operator_text<E::num < 0, Idx>() + Symbol;
if constexpr(E::den != 1) {
// add root part
return txt + basic_fixed_string("^(") + regular<abs(E::num)>() + basic_fixed_string("/") + regular<E::den>() + basic_fixed_string(")");
}
else if constexpr(abs(E::num) != 1) {
// add exponent part
return txt + superscript<abs(E::num)>();
}
else {
return txt;
}
}
template<typename... Us, typename... Es, std::size_t... Idxs>
constexpr auto deduced_symbol_text(exp_list<Es...>, std::index_sequence<Idxs...>)
{
return (exp_text<Es, Us::symbol, Idxs>() + ...);
}
template<DerivedDimension Dim, Unit... Us>
constexpr auto deduced_symbol_text()
{
return deduced_symbol_text<Us...>(typename Dim::recipe(), std::index_sequence_for<Us...>());
}
} // namespace units::detail

View File

@@ -0,0 +1,71 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/derived_dimension.h>
namespace units::detail {
// same_scaled_units
template<typename ExpList, Unit... Us>
inline constexpr bool same_scaled_units = false;
template<typename... Es, Unit... Us>
inline constexpr bool same_scaled_units<exp_list<Es...>, Us...> = (UnitOf<Us, typename Es::dimension> && ...);
// deduced_unit
template<typename Result, int UnitExpNum, int UnitExpDen, typename UnitRatio>
struct ratio_op;
template<typename Result, int UnitExpDen, typename UnitRatio>
struct ratio_op<Result, 0, UnitExpDen, UnitRatio> {
using ratio = Result;
};
template<typename Result, int UnitExpNum, int UnitExpDen, typename UnitRatio>
struct ratio_op {
using calc_ratio =
conditional<(UnitExpNum * UnitExpDen > 0), ratio_multiply<Result, UnitRatio>, ratio_divide<Result, UnitRatio>>;
static constexpr int value = (UnitExpNum * UnitExpDen > 0) ? (UnitExpNum - UnitExpDen) : (UnitExpNum + UnitExpDen);
using ratio = ratio_op<calc_ratio, value, UnitExpDen, UnitRatio>::ratio;
};
template<typename ExpList, Unit... Us>
struct derived_ratio;
template<Unit... Us>
struct derived_ratio<exp_list<>, Us...> {
using ratio = ::units::ratio<1>;
};
template<typename E, typename... ERest, Unit U, Unit... URest>
struct derived_ratio<exp_list<E, ERest...>, U, URest...> {
using rest_ratio = derived_ratio<exp_list<ERest...>, URest...>::ratio;
using ratio = ratio_op<rest_ratio, E::num, E::den, typename U::ratio>::ratio;
};
template<DerivedDimension D, Unit... Us>
using deduced_unit =
scaled_unit<typename detail::derived_ratio<typename D::recipe, Us...>::ratio, typename D::coherent_unit::reference>;
} // namespace units::detail

View File

@@ -0,0 +1,61 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/base_dimension.h>
#include <units/bits/external/downcasting.h>
#include <units/exp.h>
namespace units::detail {
/**
* @brief A dimension of a derived quantity
*
* Expression of the dependence of a quantity on the base quantities (and their base dimensions) of a system of
* quantities as a product of powers of factors corresponding to the base quantities, omitting any numerical factors.
* A power of a factor is the factor raised to an exponent.
*
* A derived dimension can be formed from multiple exponents (i.e. velocity is represented as "exp<L, 1>, exp<T, -1>").
* It is also possible to form a derived dimension with only one exponent (i.e. frequency is represented as just
* "exp<T, -1>").
*
* @note This class template is used by the library engine and should not be directly instantiated by the user.
*
* @tparam E a first exponent of a derived dimension
* @tparam ERest zero or more following exponents of a derived dimension
*/
template<Exponent E, Exponent... ERest>
requires (BaseDimension<typename E::dimension> && ... && BaseDimension<typename ERest::dimension>)
struct derived_dimension_base : downcast_base<derived_dimension_base<E, ERest...>> {
using exponents = exp_list<E, ERest...>;
};
template<typename T>
struct to_derived_dimension_base;
template<Exponent... Es>
struct to_derived_dimension_base<exp_list<Es...>> {
using type = derived_dimension_base<Es...>;
};
} // namespace units::detail

View File

@@ -0,0 +1,67 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/bits/external/type_list.h>
#include <units/exp.h>
#include <ratio> // TODO remove this dependency with #11
namespace units::detail {
/**
* @brief Consolidates contiguous ranges of exponents of the same dimension
*
* If there is more than one exponent with the same dimension they are aggregated into one exponent by adding
* their exponents. If this accumulation will result with 0, such a dimension is removed from the list.
*
* @tparam D derived dimension to consolidate
*/
template<typename ExpList>
struct dim_consolidate;
template<>
struct dim_consolidate<exp_list<>> {
using type = exp_list<>;
};
template<typename E>
struct dim_consolidate<exp_list<E>> {
using type = exp_list<E>;
};
template<typename E1, typename... ERest>
struct dim_consolidate<exp_list<E1, ERest...>> {
using type = type_list_push_front<typename dim_consolidate<exp_list<ERest...>>::type, E1>;
};
template<BaseDimension Dim, int Num1, int Den1, int Num2, int Den2, typename... ERest>
struct dim_consolidate<exp_list<exp<Dim, Num1, Den1>, exp<Dim, Num2, Den2>, ERest...>> {
// TODO: provide custom implementation for ratio_add
using r1 = std::ratio<Num1, Den1>;
using r2 = std::ratio<Num2, Den2>;
using r = std::ratio_add<r1, r2>;
using type = conditional<r::num == 0, typename dim_consolidate<exp_list<ERest...>>::type,
typename dim_consolidate<exp_list<exp<Dim, r::num, r::den>, ERest...>>::type>;
};
} // namespace units::detail

View File

@@ -22,29 +22,38 @@
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/quantity.h>
#include <units/bits/derived_dimension_base.h>
#include <units/bits/external/type_list.h>
#include <units/exp.h>
namespace units {
namespace units::detail {
struct mass : derived_dimension<mass, exp<base_dim_mass, 1>> {};
/**
* @brief Unpacks the list of potentially derived dimensions to a list containing only base dimensions
*
* @tparam Es Exponents of potentially derived dimensions
*/
template<Exponent... Es>
struct dim_unpack;
template<typename T>
concept Mass = QuantityOf<T, mass>;
template<>
struct dim_unpack<> {
using type = exp_list<>;
};
struct gram : named_scaled_derived_unit<gram, mass, "g", ratio<1, 1000>, si_prefix> {};
struct kilogram : prefixed_derived_unit<kilogram, kilo, gram> {};
template<BaseDimension Dim, int Num, int Den, Exponent... ERest>
struct dim_unpack<exp<Dim, Num, Den>, ERest...> {
using type = type_list_push_front<typename dim_unpack<ERest...>::type, exp<Dim, Num, Den>>;
};
inline namespace literals {
template<DerivedDimension Dim, int Num, int Den, Exponent... ERest>
struct dim_unpack<exp<Dim, Num, Den>, ERest...> {
using type = dim_unpack<exp<downcast_base_t<Dim>, Num, Den>, ERest...>::type;
};
// g
constexpr auto operator""g(unsigned long long l) { return quantity<gram, std::int64_t>(l); }
constexpr auto operator""g(long double l) { return quantity<gram, long double>(l); }
template<Exponent... Es, int Num, int Den, Exponent... ERest>
struct dim_unpack<exp<derived_dimension_base<Es...>, Num, Den>, ERest...> {
using type = type_list_push_front<typename dim_unpack<ERest...>::type, exp_multiply<Es, Num, Den>...>;
};
// kg
constexpr auto operator""kg(unsigned long long l) { return quantity<kilogram, std::int64_t>(l); }
constexpr auto operator""kg(long double l) { return quantity<kilogram, long double>(l); }
} // namespace literals
} // namespace units
} // namespace units::detail

View File

@@ -0,0 +1,266 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/derived_dimension.h>
#include <units/unit.h>
namespace units {
// equivalent_dim
namespace detail {
template<Dimension D1, Dimension D2>
struct equivalent_dim_impl : std::false_type {};
template<BaseDimension D1, BaseDimension D2>
struct equivalent_base_dim : std::conjunction<std::bool_constant<D1::symbol == D2::symbol>,
same_unit_reference<typename D1::base_unit, typename D2::base_unit>> {};
template<BaseDimension D1, BaseDimension D2>
struct equivalent_dim_impl<D1, D2> : std::disjunction<std::is_same<D1, D2>, equivalent_base_dim<D1, D2>> {};
template<Exponent E1, Exponent E2>
struct equivalent_exp : std::false_type {};
template<BaseDimension Dim1, int Num, int Den, BaseDimension Dim2>
struct equivalent_exp<exp<Dim1, Num, Den>, exp<Dim2, Num, Den>> : equivalent_dim_impl<Dim1, Dim2> {};
template<DerivedDimension D1, DerivedDimension D2>
struct equivalent_derived_dim : std::false_type {};
template<typename... Es1, typename... Es2>
requires (sizeof...(Es1) == sizeof...(Es2))
struct equivalent_derived_dim<derived_dimension_base<Es1...>, derived_dimension_base<Es2...>> : std::conjunction<equivalent_exp<Es1, Es2>...> {};
template<DerivedDimension D1, DerivedDimension D2>
struct equivalent_dim_impl<D1, D2> : std::disjunction<std::is_same<D1, D2>, equivalent_derived_dim<downcast_base_t<D1>, downcast_base_t<D2>>> {};
} // namespace detail
template<Dimension D1, Dimension D2>
inline constexpr bool equivalent_dim = detail::equivalent_dim_impl<D1, D2>::value;
/**
* @brief Unknown dimension
*
* Sometimes a temporary partial result of a complex calculation may not result in a predefined
* dimension. In such a case an `unknown_dimension` is created with a coherent unit of `unknown_unit`
* and ratio<1>.
*
* @tparam E the list of exponents of ingredient dimensions
* @tparam ERest the list of exponents of ingredient dimensions
*/
template<Exponent E, Exponent... ERest>
struct unknown_dimension : derived_dimension<unknown_dimension<E, ERest...>, scaled_unit<ratio<1>, unknown_unit>, E, ERest...> {
using coherent_unit = scaled_unit<ratio<1>, unknown_unit>;
};
namespace detail {
template<DerivedDimension D>
struct check_unknown {
using type = D;
};
// downcast did not find a user predefined type
template<typename... Es>
struct check_unknown<derived_dimension_base<Es...>> {
using type = unknown_dimension<Es...>;
};
template<Dimension D>
struct downcast_dimension_impl;
template<BaseDimension D>
struct downcast_dimension_impl<D> {
using type = D;
};
template<DerivedDimension D>
struct downcast_dimension_impl<D> {
using type = check_unknown<downcast<D>>::type;
};
} // namespace detail
template<Dimension D>
using downcast_dimension = detail::downcast_dimension_impl<D>::type;
// dim_invert
namespace detail {
template<Dimension D>
struct dim_invert_impl;
template<BaseDimension D>
struct dim_invert_impl<D> {
using type = downcast_dimension<derived_dimension_base<exp<D, -1>>>;
};
template<BaseDimension D>
struct dim_invert_impl<derived_dimension_base<exp<D, -1>>> {
using type = D;
};
template<typename... Es>
struct dim_invert_impl<derived_dimension_base<Es...>> {
using type = downcast_dimension<derived_dimension_base<exp_invert<Es>...>>;
};
template<DerivedDimension D>
struct dim_invert_impl<D> : dim_invert_impl<downcast_base_t<D>> {
};
} // namespace detail
template<Dimension D>
using dim_invert = detail::dim_invert_impl<D>::type;
// dimension_multiply
namespace detail {
template<typename T>
struct to_dimension;
template<Exponent... Es>
struct to_dimension<exp_list<Es...>> {
using type = derived_dimension_base<Es...>;
};
template<BaseDimension D>
struct to_dimension<exp_list<exp<D, 1>>> {
using type = D;
};
/**
* @brief Merges 2 sorted derived dimensions into one units::derived_dimension_base
*
* A result of a dimensional calculation may result with many exponents of the same base dimension orginated
* from different parts of the equation. As the exponents lists of both operands it is enough to merge them
* into one list and consolidate duplicates. Also it is possible that final exponents list will contain only
* one element being a base dimension with exponent 1. In such a case the final dimension should be the base
* dimension itself.
*/
template<Dimension D1, Dimension D2>
using merge_dimension = to_dimension<typename dim_consolidate<type_list_merge_sorted<typename D1::exponents, typename D2::exponents, exp_less>>::type>::type;
template<Dimension D1, Dimension D2>
struct dimension_multiply_impl;
template<BaseDimension D1, BaseDimension D2>
struct dimension_multiply_impl<D1, D2> {
using type = downcast_dimension<merge_dimension<derived_dimension_base<exp<D1, 1>>, derived_dimension_base<exp<D2, 1>>>>;
};
template<BaseDimension D1, DerivedDimension D2>
struct dimension_multiply_impl<D1, D2> {
using type = downcast_dimension<merge_dimension<derived_dimension_base<exp<D1, 1>>, typename D2::downcast_base_type>>;
};
template<DerivedDimension D1, BaseDimension D2>
struct dimension_multiply_impl<D1, D2> {
using type = dimension_multiply_impl<D2, D1>::type;
};
template<DerivedDimension D1, DerivedDimension D2>
struct dimension_multiply_impl<D1, D2> {
using type = downcast_dimension<merge_dimension<typename D1::downcast_base_type, typename D2::downcast_base_type>>;
};
} // namespace detail
template<Dimension D1, Dimension D2>
using dimension_multiply = detail::dimension_multiply_impl<D1, D2>::type;
template<Dimension D1, Dimension D2>
using dimension_divide = detail::dimension_multiply_impl<D1, dim_invert<D2>>::type;
// dimension_sqrt
namespace detail {
template<Dimension D>
struct dimension_sqrt_impl;
template<BaseDimension D>
struct dimension_sqrt_impl<D> {
using type = downcast_dimension<derived_dimension_base<exp<D, 1, 2>>>;
};
template<BaseDimension D>
struct dimension_sqrt_impl<derived_dimension_base<exp<D, 2>>> {
using type = D;
};
template<DerivedDimension D>
struct dimension_sqrt_impl<D> {
using type = dimension_sqrt_impl<typename D::downcast_base_type>::type;
};
template<typename... Es>
struct dimension_sqrt_impl<derived_dimension_base<Es...>> {
using type = downcast_dimension<derived_dimension_base<exp_multiply<Es, 1, 2>...>>;
};
} // namespace detail
template<Dimension D>
using dimension_sqrt = detail::dimension_sqrt_impl<D>::type;
// dimension_pow
namespace detail {
template<Dimension D, std::size_t N>
struct dimension_pow_impl;
template<BaseDimension D, std::size_t N>
struct dimension_pow_impl<D, N> {
using type = downcast_dimension<derived_dimension_base<exp<D, N>>>;
};
template<BaseDimension D>
struct dimension_pow_impl<D, 1> {
using type = D;
};
template<BaseDimension D, std::size_t N>
struct dimension_pow_impl<derived_dimension_base<exp<D, 1, N>>, N> {
using type = D;
};
template<DerivedDimension D, std::size_t N>
struct dimension_pow_impl<D, N> {
using type = dimension_pow_impl<downcast_base_t<D>, N>::type;
};
template<typename... Es, std::size_t N>
struct dimension_pow_impl<derived_dimension_base<Es...>, N> {
using type = downcast_dimension<derived_dimension_base<exp_multiply<Es, N, 1>...>>;
};
} // namespace detail
template<Dimension D, std::size_t N>
using dimension_pow = detail::dimension_pow_impl<D, N>::type;
} // namespace units

View File

@@ -22,23 +22,23 @@
#pragma once
#include <units/bits/hacks.h>
#include <units/bits/external/hacks.h>
#include <type_traits>
namespace units {
template<typename BaseType>
struct downcast_base {
using base_type = BaseType;
using downcast_base_type = BaseType;
friend auto downcast_guide(downcast_base);
};
template<typename T>
concept Downcastable =
requires {
typename T::base_type;
typename T::downcast_base_type;
} &&
std::derived_from<T, downcast_base<typename T::base_type>>;
std::derived_from<T, downcast_base<typename T::downcast_base_type>>;
template<typename Target, Downcastable T>
struct downcast_child : T {
@@ -67,6 +67,6 @@ namespace units {
using downcast = decltype(detail::downcast_impl<T>());
template<Downcastable T>
using downcast_base_t = T::base_type;
using downcast_base_t = T::downcast_base_type;
} // namespace units

View File

@@ -22,7 +22,6 @@
#pragma once
#include <concepts/concepts.hpp>
#include <functional>
#ifdef NDEBUG
@@ -32,16 +31,24 @@
#define Expects(cond) assert(cond);
#endif
#if __GNUC__ > 9
#define AUTO auto
#define SAME_AS(T) std::same_as<T>
#else
#if __GNUC__ < 10
#include <concepts/concepts.hpp>
#define AUTO
#define SAME_AS(T) T
#else
#include <concepts>
#define AUTO auto
#define SAME_AS(T) std::same_as<T>
#endif
namespace std {
#if __GNUC__ < 10
// concepts
using concepts::common_reference_with;
using concepts::common_with;
@@ -64,4 +71,11 @@ namespace std {
template<class F, class... Args>
concept regular_invocable = invocable<F, Args...>;
}
#else
template<class T>
concept default_constructible = constructible_from<T>;
#endif
} // namespace std

View File

@@ -22,7 +22,7 @@
#pragma once
#include <units/bits/hacks.h>
#include <units/bits/external/hacks.h>
// P1813 - A Concept Design for the Numeric Algorithms

View File

@@ -0,0 +1,64 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/bits/external/fixed_string.h>
namespace units::detail {
template<int Value>
requires (0 <= Value) && (Value < 10)
inline constexpr basic_fixed_string superscript_number = "";
template<> inline constexpr basic_fixed_string superscript_number<0> = "\u2070";
template<> inline constexpr basic_fixed_string superscript_number<1> = "\u00b9";
template<> inline constexpr basic_fixed_string superscript_number<2> = "\u00b2";
template<> inline constexpr basic_fixed_string superscript_number<3> = "\u00b3";
template<> inline constexpr basic_fixed_string superscript_number<4> = "\u2074";
template<> inline constexpr basic_fixed_string superscript_number<5> = "\u2075";
template<> inline constexpr basic_fixed_string superscript_number<6> = "\u2076";
template<> inline constexpr basic_fixed_string superscript_number<7> = "\u2077";
template<> inline constexpr basic_fixed_string superscript_number<8> = "\u2078";
template<> inline constexpr basic_fixed_string superscript_number<9> = "\u2079";
template<int Value>
requires (Value >= 0)
constexpr auto superscript()
{
if constexpr(Value < 10)
return superscript_number<Value>;
else
return superscript<Value / 10>() + superscript<Value % 10>();
}
template<int Value>
requires (Value >= 0)
constexpr auto regular()
{
if constexpr(Value < 10)
return basic_fixed_string(static_cast<char>('0' + Value));
else
return regular<Value / 10>() + regular<Value % 10>();
}
} // namespace units::detail

View File

@@ -22,7 +22,7 @@
#pragma once
#include <units/bits/type_traits.h>
#include <units/bits/external/type_traits.h>
namespace units {

View File

@@ -0,0 +1,78 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <type_traits>
namespace units {
// conditional
namespace detail {
template<bool>
struct conditional_impl {
template<typename T, typename F>
using type = F;
};
template<>
struct conditional_impl<true> {
template<typename T, typename F>
using type = T;
};
} // namespace detail
template<bool B, typename T, typename F>
using conditional = detail::conditional_impl<B>::template type<T, F>;
// is_instantiation
namespace detail {
template<typename T, template<typename...> typename Type>
inline constexpr bool is_instantiation_impl = false;
template<typename... Params, template<typename...> typename Type>
inline constexpr bool is_instantiation_impl<Type<Params...>, Type> = true;
} // namespace detail
template<typename T, template<typename...> typename Type>
inline constexpr bool is_instantiation = detail::is_instantiation_impl<T, Type>;
// is_derived_from_instantiation
namespace detail {
template<template<typename...> typename Type>
struct is_derived_from_instantiation_impl {
template<typename... Params>
static constexpr std::true_type check_base(const Type<Params...>&);
static constexpr std::true_type check_base(...);
};
} // namespace detail
template<typename T, template<typename...> typename Type>
inline constexpr bool is_derived_from_instantiation = decltype(detail::is_derived_from_instantiation_impl<Type>::check_base(std::declval<T>()))::value;
} // namespace units

View File

@@ -0,0 +1,128 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/derived_dimension.h>
namespace units::detail {
template<typename Ratio>
constexpr auto ratio_text()
{
if constexpr(Ratio::num != 1 || Ratio::den != 1) {
auto txt = basic_fixed_string("[") + regular<Ratio::num>();
if constexpr(Ratio::den == 1) {
return txt + basic_fixed_string("]");
}
else {
return txt + basic_fixed_string("/") + regular<Ratio::den>() + basic_fixed_string("]");
}
}
else {
return basic_fixed_string("");
}
}
template<typename Ratio, typename PrefixType>
constexpr auto prefix_or_ratio_text()
{
if constexpr(Ratio::num == 1 && Ratio::den == 1) {
// no ratio/prefix
return basic_fixed_string("");
}
else {
if constexpr (!std::same_as<PrefixType, no_prefix>) {
// try to form a prefix
using prefix = downcast<detail::prefix_base<PrefixType, Ratio>>;
if constexpr(!std::same_as<prefix, prefix_base<PrefixType, Ratio>>) {
// print as a prefixed unit
return prefix::symbol;
}
else {
// print as a ratio of the coherent unit
return ratio_text<Ratio>();
}
}
else {
// print as a ratio of the coherent unit
return ratio_text<Ratio>();
}
}
}
template<typename... Es, std::size_t... Idxs>
constexpr auto derived_dimension_unit_text(exp_list<Es...>, std::index_sequence<Idxs...>)
{
return (exp_text<Es, dimension_unit<typename Es::dimension>::symbol, Idxs>() + ...);
}
template<typename... Es>
constexpr auto derived_dimension_unit_text(exp_list<Es...> list)
{
return derived_dimension_unit_text(list, std::index_sequence_for<Es...>());
}
template<typename... Es>
constexpr bool all_named(exp_list<Es...>)
{
return (dimension_unit<typename Es::dimension>::is_named && ...);
}
template<Dimension Dim>
constexpr auto derived_dimension_unit_text()
{
using recipe = typename Dim::recipe;
if constexpr(all_named(recipe()))
return derived_dimension_unit_text(recipe());
else
return derived_dimension_unit_text(typename Dim::exponents());
}
// TODO Inline below concept when switched to gcc-10
template<typename T>
concept has_symbol = requires{ T::symbol; };
template<Dimension Dim, Unit U>
constexpr auto unit_text()
{
if constexpr(has_symbol<U>) {
// already has a symbol so print it
return U::symbol;
}
else {
// print as a prefix or ratio of a reference unit
auto prefix_txt = prefix_or_ratio_text<typename U::ratio, typename U::reference::prefix_type>();
if constexpr(has_symbol<typename U::reference>) {
// use predefined reference unit symbol
return prefix_txt + U::reference::symbol;
}
else {
// use derived dimension ingredients to create a unit symbol
return prefix_txt + derived_dimension_unit_text<Dim>();
}
}
}
} // namespace units::detail

View File

@@ -0,0 +1,187 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/bits/external/downcasting.h>
#include <units/bits/external/fixed_string.h>
#include <units/bits/external/hacks.h>
#include <units/bits/external/numeric_concepts.h>
#include <units/bits/external/type_traits.h>
#include <units/customization_points.h>
namespace units {
namespace detail {
template<typename T, typename U = T>
concept basic_arithmetic = // exposition only
std::magma<std::ranges::plus, T, U> &&
std::magma<std::ranges::minus, T, U> &&
std::magma<std::ranges::times, T, U> &&
std::magma<std::ranges::divided_by, T, U>;
} // namespace detail
// PrefixType
struct prefix_type;
template<typename T>
concept PrefixType = std::derived_from<T, prefix_type>;
// Prefix
// TODO gcc:92150
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92150
// namespace detail {
// template<typename T>
// inline constexpr bool is_prefix = false;
// template<typename PrefixType, Ratio R, basic_fixed_string Symbol>
// inline constexpr bool is_prefix<prefix<PrefixType, R, Symbol>> = true;
// } // namespace detail
template<typename T>
// concept Prefix = detail::is_prefix<T>;
concept Prefix = true;
namespace detail {
template<typename T>
inline constexpr bool is_ratio = false;
} // namespace detail
template<typename T>
concept Ratio = detail::is_ratio<T>;
// UnitRatio
template<typename R>
concept UnitRatio = Ratio<R> && (R::num * R::den > 0);
// Unit
template<UnitRatio R, typename U>
struct scaled_unit;
template<typename T>
concept Unit = is_derived_from_instantiation<T, scaled_unit>;
// BaseDimension
template<basic_fixed_string Symbol, Unit U>
requires U::is_named
struct base_dimension;
namespace detail {
#if __GNUC__ == 9 && __GNUC_MINOR__ < 2
template<typename T>
inline constexpr bool is_base_dimension = true;
#else
template<typename T>
inline constexpr bool is_base_dimension = false;
template<basic_fixed_string Name, typename... Params>
inline constexpr bool is_base_dimension<base_dimension<Name, Params...>> = true;
#endif
} // namespace detail
template<typename T>
concept BaseDimension = detail::is_base_dimension<typename T::base_type_workaround>;
// Exponent
namespace detail {
template<typename T>
inline constexpr bool is_exp = false;
} // namespace detail
template<typename T>
concept Exponent = detail::is_exp<T>;
// DerivedDimension
namespace detail {
template<Exponent E, Exponent... ERest>
requires (BaseDimension<typename E::dimension> && ... && BaseDimension<typename ERest::dimension>)
struct derived_dimension_base;
} // namespace detail
template<typename T>
concept DerivedDimension = is_instantiation<downcast_base_t<T>, detail::derived_dimension_base>;
// Dimension
template<typename T>
concept Dimension = BaseDimension<T> || DerivedDimension<T>;
// UnitOf
namespace detail {
template<Dimension D>
struct dimension_unit_impl;
template<BaseDimension D>
struct dimension_unit_impl<D> {
using type = D::base_unit;
};
template<DerivedDimension D>
struct dimension_unit_impl<D> {
using type = D::coherent_unit;
};
} // namespace detail
template<Dimension D>
using dimension_unit = detail::dimension_unit_impl<D>::type;
template<typename U, typename D>
concept UnitOf =
Unit<U> &&
Dimension<D> &&
std::same_as<typename U::reference, typename dimension_unit<D>::reference>;
// Quantity
namespace detail {
template<typename T>
inline constexpr bool is_quantity = false;
} // namespace detail
template<typename T>
concept Quantity = detail::is_quantity<T>;
// Scalar
template<typename T>
concept Scalar = (!Quantity<T>) && std::regular<T> && std::totally_ordered<T> && detail::basic_arithmetic<T>;
} // namespace units

View File

@@ -0,0 +1,141 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <limits>
#include <type_traits>
namespace units {
/**
* @brief Specifies if a value of a type should be treated as a floating-point value
*
* This type trait should be specialized for a custom representation type to specify
* that values fo this type should be treated by the library as a floating-point ones
* which will enable implicit conversions between quantities.
*
* @tparam Rep a representation type for which a type trait is defined
*/
template<typename Rep>
inline constexpr bool treat_as_floating_point = std::is_floating_point_v<Rep>;
/**
* @brief A type trait that defines zero, one, min, and max for a representation type
*
* The zero, one, min, and max member functions in units::quantity forward their work to
* these methods. This type can be specialized if the representation Rep requires a specific
* implementation to return these quantity objects.
*
* @tparam Rep a representation type for which a type trait is defined
*/
template<typename Rep>
struct quantity_values {
static constexpr Rep zero() noexcept { return Rep(0); }
static constexpr Rep one() noexcept { return Rep(1); }
static constexpr Rep min() noexcept { return std::numeric_limits<Rep>::lowest(); }
static constexpr Rep max() noexcept { return std::numeric_limits<Rep>::max(); }
};
// // isnan
// namespace isnan_impl {
// // non-ADL lookup block
// void isnan(); // undefined
// template<typename>
// inline constexpr bool has_customization = false;
// template<typename T>
// requires requires(const T& t) {
// { isnan(t) } -> bool;
// }
// inline constexpr bool has_customization<T> = true;
// struct fn {
// template<typename T>
// constexpr bool operator()(const T&) const
// {
// return false;
// }
// template<typename T>
// requires treat_as_floating_point<T>
// constexpr bool operator()(const T& value) const
// {
// return std::isnan(value);
// }
// template<typename T>
// requires treat_as_floating_point<T> && has_customization<T>
// constexpr bool operator()(const T& value) const
// {
// return isnan(value); // uses ADL
// }
// };
// }
// inline constexpr isnan_impl::fn isnan{};
// // isfinite
// namespace isfinite_impl {
// // non-ADL lookup block
// void isfinite(); // undefined
// template<typename>
// inline constexpr bool has_customization = false;
// template<typename T>
// requires requires(const T& t) {
// { isfinite(t) } -> bool;
// }
// inline constexpr bool has_customization<T> = true;
// struct fn {
// template<typename T>
// constexpr bool operator()(const T&) const
// {
// return true;
// }
// template<typename T>
// requires treat_as_floating_point<T>
// constexpr bool operator()(const T& value) const
// {
// return std::isfinite(value);
// }
// template<typename T>
// requires treat_as_floating_point<T> && has_customization<T>
// constexpr bool operator()(const T& value) const
// {
// return isfinite(value); // uses ADL
// }
// };
// }
// inline constexpr isfinite_impl::fn isfinite{};
} // namespace units

View File

@@ -0,0 +1,59 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/data/information.h>
#include <units/derived_dimension.h>
#include <units/physical/si/time.h>
#include <units/quantity.h>
namespace units::data {
struct bit_per_second : unit<bit_per_second> {};
struct dim_bitrate : derived_dimension<dim_bitrate, bit_per_second, exp<dim_information, 1>, exp<si::dim_time, -1>> {};
struct kibibit_per_second : deduced_unit<kibibit_per_second, dim_bitrate, kibibit, si::second> {};
struct mebibit_per_second : deduced_unit<mebibit_per_second, dim_bitrate, mebibit, si::second> {};
struct gibibit_per_second : deduced_unit<gibibit_per_second, dim_bitrate, gibibit, si::second> {};
struct tebibit_per_second : deduced_unit<tebibit_per_second, dim_bitrate, tebibit, si::second> {};
struct pebibit_per_second : deduced_unit<pebibit_per_second, dim_bitrate, pebibit, si::second> {};
template<typename T>
concept Bitrate = QuantityOf<T, dim_bitrate>;
template<Unit U, Scalar Rep = double>
using bitrate = quantity<dim_bitrate, U, Rep>;
inline namespace literals {
// bits
constexpr auto operator""_bps(unsigned long long l) { return bitrate<bit_per_second, std::int64_t>(l); }
constexpr auto operator""_Kibps(unsigned long long l) { return bitrate<kibibit_per_second, std::int64_t>(l); }
constexpr auto operator""_Mibps(unsigned long long l) { return bitrate<mebibit_per_second, std::int64_t>(l); }
constexpr auto operator""_Gibps(unsigned long long l) { return bitrate<gibibit_per_second, std::int64_t>(l); }
constexpr auto operator""_Tibps(unsigned long long l) { return bitrate<tebibit_per_second, std::int64_t>(l); }
constexpr auto operator""_Pibps(unsigned long long l) { return bitrate<pebibit_per_second, std::int64_t>(l); }
} // namespace literals
} // namespace units::data

View File

@@ -0,0 +1,74 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/base_dimension.h>
#include <units/data/prefixes.h>
#include <units/unit.h>
#include <units/quantity.h>
namespace units::data {
struct bit : named_unit<bit, "b", prefix> {};
struct kibibit : prefixed_unit<kibibit, kibi, bit> {};
struct mebibit : prefixed_unit<mebibit, mebi, bit> {};
struct gibibit : prefixed_unit<gibibit, gibi, bit> {};
struct tebibit : prefixed_unit<tebibit, tebi, bit> {};
struct pebibit : prefixed_unit<pebibit, pebi, bit> {};
struct byte : named_scaled_unit<byte, "B", prefix, ratio<8>, bit> {};
struct kibibyte : prefixed_unit<kibibyte, kibi, byte> {};
struct mebibyte : prefixed_unit<mebibyte, mebi, byte> {};
struct gibibyte : prefixed_unit<gibibyte, gibi, byte> {};
struct tebibyte : prefixed_unit<tebibyte, tebi, byte> {};
struct pebibyte : prefixed_unit<pebibyte, pebi, byte> {};
struct dim_information : base_dimension<"information", bit> {};
template<typename T>
concept Information = QuantityOf<T, dim_information>;
template<Unit U, Scalar Rep = double>
using information = quantity<dim_information, U, Rep>;
inline namespace literals {
// bits
constexpr auto operator""b(unsigned long long l) { return information<bit, std::int64_t>(l); }
constexpr auto operator""Kib(unsigned long long l) { return information<kibibit, std::int64_t>(l); }
constexpr auto operator""Mib(unsigned long long l) { return information<mebibit, std::int64_t>(l); }
constexpr auto operator""Gib(unsigned long long l) { return information<gibibit, std::int64_t>(l); }
constexpr auto operator""Tib(unsigned long long l) { return information<tebibit, std::int64_t>(l); }
constexpr auto operator""Pib(unsigned long long l) { return information<pebibit, std::int64_t>(l); }
// bytes
constexpr auto operator""B(unsigned long long l) { return information<byte, std::int64_t>(l); }
constexpr auto operator""KiB(unsigned long long l) { return information<kibibyte, std::int64_t>(l); }
constexpr auto operator""MiB(unsigned long long l) { return information<mebibyte, std::int64_t>(l); }
constexpr auto operator""GiB(unsigned long long l) { return information<gibibyte, std::int64_t>(l); }
constexpr auto operator""TiB(unsigned long long l) { return information<tebibyte, std::int64_t>(l); }
constexpr auto operator""PiB(unsigned long long l) { return information<pebibyte, std::int64_t>(l); }
} // namespace literals
} // namespace units::data

View File

@@ -22,23 +22,18 @@
#pragma once
#include <units/dimensions/velocity.h>
#include <units/prefix.h>
#include <ratio>
namespace units {
namespace units::data {
struct acceleration : derived_dimension<acceleration, exp<velocity, 1>, exp<time, -1>> {};
struct prefix : prefix_type {};
template<typename T>
concept Acceleration = QuantityOf<T, acceleration>;
struct kibi : units::prefix<kibi, prefix, "Ki", ratio< 1'024>> {};
struct mebi : units::prefix<mebi, prefix, "Mi", ratio< 1'048'576>> {};
struct gibi : units::prefix<gibi, prefix, "Gi", ratio< 1'073'741'824>> {};
struct tebi : units::prefix<tebi, prefix, "Ti", ratio< 1'099'511'627'776>> {};
struct pebi : units::prefix<pebi, prefix, "Pi", ratio< 1'125'899'906'842'624>> {};
struct exbi : units::prefix<exbi, prefix, "Ei", ratio<1'152'921'504'606'846'976>> {};
struct metre_per_second_sq : coherent_derived_unit<metre_per_second_sq, acceleration> {};
inline namespace literals {
// mps_sq
constexpr auto operator""mps_sq(unsigned long long l) { return quantity<metre_per_second_sq, std::int64_t>(l); }
constexpr auto operator""mps_sq(long double l) { return quantity<metre_per_second_sq, long double>(l); }
} // namespace literals
} // namespace units
} // namespace units::si

View File

@@ -0,0 +1,78 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/base_dimension.h>
#include <units/bits/base_units_ratio.h>
#include <units/bits/derived_dimension_base.h>
#include <units/bits/dim_consolidate.h>
#include <units/bits/dim_unpack.h>
#include <units/bits/external/downcasting.h>
#include <units/bits/external/type_list.h>
#include <units/exp.h>
namespace units {
namespace detail {
/**
* @brief Converts user provided derived dimension specification into a valid units::derived_dimension_base definition
*
* User provided definition of a derived dimension may contain the same base dimension repeated more than once on the
* list possibly hidden in other derived units provided by the user. The process here should:
* 1. Extract derived dimensions into exponents of base dimensions.
* 2. Sort the exponents so the same dimensions are placed next to each other.
* 3. Consolidate contiguous range of exponents of the same base dimensions to a one (or possibly zero) exponent for
* this base dimension.
*/
template<Exponent... Es>
using make_dimension = to_derived_dimension_base<typename dim_consolidate<type_list_sort<typename dim_unpack<Es...>::type, exp_less>>::type>::type;
} // namespace detail
/**
* @brief The list of exponents of dimensions (both base and derived) provided by the user
*
* This is the user's interface to create derived dimensions. Exponents list can contain powers of factors of both
* base and derived dimensions. This is called a "recipe" of the dimension and among others is used to print
* unnamed coherent units of this dimension.
*
* Coherent unit is a unit that, for a given system of quantities and for a chosen set of base units, is a product
* of powers of base units with no other proportionality factor than one.
*
* The implementation is responsible for unpacking all of the dimensions into a list containing only base dimensions
* and their factors and putting them to derived_dimension_base class template.
*
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
* @tparam U a coherent unit of a derived dimension
* @tparam E the list of exponents of ingredient dimensions
* @tparam ERest the list of exponents of ingredient dimensions
*/
template<typename Child, Unit U, Exponent E, Exponent... ERest>
struct derived_dimension : downcast_child<Child, typename detail::make_dimension<E, ERest...>> {
using recipe = exp_list<E, ERest...>;
using coherent_unit = U;
using base_units_ratio = detail::base_units_ratio<derived_dimension>;
};
} // namespace units

View File

@@ -1,292 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/bits/type_list.h>
#include <units/bits/downcasting.h>
#include <units/bits/fixed_string.h>
#include <units/ratio.h>
#include <ratio>
namespace units {
template<basic_fixed_string Name, basic_fixed_string Symbol>
struct base_dimension {
static constexpr auto name = Name;
static constexpr auto symbol = Symbol;
};
template<typename T>
concept BaseDimension = std::is_empty_v<T> &&
requires {
T::name;
T::symbol;
};// && // TODO file a bug for this gcc issue
// std::derived_from<T, base_dimension<T::name, T::symbol>>;
// base_dimension_less
template<BaseDimension D1, BaseDimension D2>
struct base_dimension_less : std::bool_constant<D1::name < D2::name> {
};
// is_exp
namespace detail {
template<typename T>
inline constexpr bool is_exp = false;
// partial specialization for an exp type provided below
} // namespace detail
template<typename T>
concept Exponent = detail::is_exp<T>;
template<Exponent... Es>
struct dimension;
// is_dimension
namespace detail {
template<typename T>
inline constexpr bool is_dimension = false;
template<typename... Es>
inline constexpr bool is_dimension<dimension<Es...>> = true;
} // namespace detail
template<typename T>
concept Dimension =
std::is_empty_v<T> &&
detail::is_dimension<downcast_base_t<T>>;
// exp
template<typename BaseOrDim, int Num, int Den = 1>
requires BaseDimension<BaseOrDim> || Dimension<BaseOrDim>
struct exp {
using dimension = BaseOrDim;
static constexpr int num = Num;
static constexpr int den = Den;
};
// is_exp
namespace detail {
template<typename Dim, int Num, int Den>
inline constexpr bool is_exp<exp<Dim, Num, Den>> = true;
} // namespace detail
// exp_less
template<Exponent E1, Exponent E2>
struct exp_less : base_dimension_less<typename E1::dimension, typename E2::dimension> {
};
// exp_invert
namespace detail {
template<Exponent E>
struct exp_invert_impl;
template<typename Dim, int Num, int Den>
struct exp_invert_impl<exp<Dim, Num, Den>> {
using type = exp<Dim, -Num, Den>;
};
}
template<Exponent E>
using exp_invert = detail::exp_invert_impl<E>::type;
// exp_multiply
namespace detail {
template<Exponent E, int Num, int Den>
struct exp_multiply_impl {
using r1 = ratio<E::num, E::den>;
using r2 = ratio<Num, Den>;
using r = ratio_multiply<r1, r2>;
using type = exp<typename E::dimension, r::num, r::den>;
};
}
template<Exponent E, int Num, int Den>
using exp_multiply = detail::exp_multiply_impl<E, Num, Den>::type;
// dimension
template<Exponent... Es>
struct dimension : downcast_base<dimension<Es...>> {};
// same_dim
template<typename D1, Dimension D2>
requires BaseDimension<D1> || Dimension<D1>
inline constexpr bool same_dim = std::is_same_v<typename D1::base_type, typename D2::base_type>;
template<BaseDimension D1, Dimension D2>
inline constexpr bool same_dim<D1, D2> = std::is_same_v<dimension<units::exp<D1, 1>>, typename D2::base_type>;
// dim_invert
namespace detail {
template<Dimension E>
struct dim_invert_impl;
template<typename... Es>
struct dim_invert_impl<dimension<Es...>> : std::type_identity<downcast<dimension<exp_invert<Es>...>>> {};
}
template<Dimension D>
using dim_invert = detail::dim_invert_impl<downcast_base_t<D>>::type;
// make_dimension
namespace detail {
template<Dimension D>
struct dim_consolidate;
template<>
struct dim_consolidate<dimension<>> {
using type = dimension<>;
};
template<typename E>
struct dim_consolidate<dimension<E>> {
using type = dimension<E>;
};
template<typename E1, typename... ERest>
struct dim_consolidate<dimension<E1, ERest...>> {
using type = type_list_push_front<typename dim_consolidate<dimension<ERest...>>::type, E1>;
};
template<BaseDimension D, int Num1, int Den1, int Num2, int Den2, typename... ERest>
struct dim_consolidate<dimension<exp<D, Num1, Den1>, exp<D, Num2, Den2>, ERest...>> {
// TODO: provide custom implementation for ratio_add
using r1 = std::ratio<Num1, Den1>;
using r2 = std::ratio<Num2, Den2>;
using r = std::ratio_add<r1, r2>;
using type = conditional<r::num == 0, typename dim_consolidate<dimension<ERest...>>::type,
typename dim_consolidate<dimension<exp<D, r::num, r::den>, ERest...>>::type>;
};
template<Exponent... Es>
struct extract;
template<>
struct extract<> {
using type = dimension<>;
};
template<BaseDimension Dim, int Num, int Den, Exponent... ERest>
struct extract<exp<Dim, Num, Den>, ERest...> {
using type = type_list_push_front<typename extract<ERest...>::type, exp<Dim, Num, Den>>;
};
template<Exponent... Es, int Num, int Den, Exponent... ERest>
struct extract<exp<dimension<Es...>, Num, Den>, ERest...> {
using type = type_list_push_front<typename extract<ERest...>::type, exp_multiply<Es, Num, Den>...>;
};
template<Dimension Dim, int Num, int Den, Exponent... ERest>
struct extract<exp<Dim, Num, Den>, ERest...> {
using type = extract<exp<downcast_base_t<Dim>, Num, Den>, ERest...>::type;
};
template<Exponent... Es>
using make_dimension = dim_consolidate<type_list_sort<typename extract<Es...>::type, exp_less>>::type;
} // namespace detail
// derived_dimension
template<typename Child, Exponent... Es>
struct derived_dimension : downcast_child<Child, typename detail::make_dimension<Es...>> {
using recipe = dimension<Es...>;
};
// merge_dimension
template<Dimension D1, Dimension D2>
using merge_dimension = detail::dim_consolidate<type_list_merge_sorted<D1, D2, exp_less>>::type;
// dimension_multiply
namespace detail {
template<typename D1, typename D2>
struct dimension_multiply_impl;
template<typename... E1, typename... E2>
struct dimension_multiply_impl<dimension<E1...>, dimension<E2...>> : std::type_identity<downcast<merge_dimension<dimension<E1...>, dimension<E2...>>>> {};
}
template<Dimension D1, Dimension D2>
using dimension_multiply = detail::dimension_multiply_impl<typename D1::base_type, typename D2::base_type>::type;
// dimension_divide
namespace detail {
template<typename D1, typename D2>
struct dimension_divide_impl;
template<typename... E1, typename... E2>
struct dimension_divide_impl<dimension<E1...>, dimension<E2...>>
: dimension_multiply_impl<dimension<E1...>, dimension<exp_invert<E2>...>> {
};
}
template<Dimension D1, Dimension D2>
using dimension_divide = detail::dimension_divide_impl<typename D1::base_type, typename D2::base_type>::type;
// dimension_sqrt
namespace detail {
template<typename D>
struct dimension_sqrt_impl;
template<typename... Es>
struct dimension_sqrt_impl<dimension<Es...>> : std::type_identity<downcast<dimension<exp_multiply<Es, 1, 2>...>>> {};
}
template<Dimension D>
using dimension_sqrt = detail::dimension_sqrt_impl<typename D::base_type>::type;
// dimension_pow
namespace detail {
template<typename D, std::size_t N>
struct dimension_pow_impl;
template<typename... Es, std::size_t N>
struct dimension_pow_impl<dimension<Es...>, N> : std::type_identity<downcast<dimension<exp_multiply<Es, N, 1>...>>> {};
}
template<Dimension D, std::size_t N>
using dimension_pow = detail::dimension_pow_impl<typename D::base_type, N>::type;
} // namespace units

View File

@@ -1,64 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/length.h>
namespace units {
struct area : derived_dimension<area, exp<length, 2>> {};
template<typename T>
concept Area = QuantityOf<T, area>;
struct square_metre : coherent_derived_unit<square_metre, area> {};
struct square_millimetre : deduced_derived_unit<square_millimetre, area, millimetre> {};
struct square_centimetre : deduced_derived_unit<square_centimetre, area, centimetre> {};
struct square_kilometre : deduced_derived_unit<square_kilometre, area, kilometre> {};
struct square_foot : deduced_derived_unit<square_foot, area, foot> {};
inline namespace literals {
// sq_m
constexpr auto operator""sq_m(unsigned long long l) { return quantity<square_metre, std::int64_t>(l); }
constexpr auto operator""sq_m(long double l) { return quantity<square_metre, long double>(l); }
// sq_mm
constexpr auto operator""sq_mm(unsigned long long l) { return quantity<square_millimetre, std::int64_t>(l); }
constexpr auto operator""sq_mm(long double l) { return quantity<square_millimetre, long double>(l); }
// sq_cm
constexpr auto operator""sq_cm(unsigned long long l) { return quantity<square_centimetre, std::int64_t>(l); }
constexpr auto operator""sq_cm(long double l) { return quantity<square_centimetre, long double>(l); }
// sq_km
constexpr auto operator""sq_km(unsigned long long l) { return quantity<square_kilometre, std::int64_t>(l); }
constexpr auto operator""sq_km(long double l) { return quantity<square_kilometre, long double>(l); }
// sq_ft
constexpr auto operator""sq_ft(unsigned long long l) { return quantity<square_foot, std::int64_t>(l); }
constexpr auto operator""sq_ft(long double l) { return quantity<square_foot, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,46 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/electric_charge.h>
#include <units/dimensions/voltage.h>
namespace units {
struct capacitance : derived_dimension<capacitance, exp<electric_charge, 1>, exp<voltage, -1>> {};
template<typename T>
concept Capacitance = QuantityOf<T, capacitance>;
struct farad : named_coherent_derived_unit<farad, capacitance, "F", si_prefix> {};
inline namespace literals {
// F
constexpr auto operator""F(unsigned long long l) { return quantity<farad, std::int64_t>(l); }
constexpr auto operator""_F(long double l) { return quantity<farad, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,46 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/time.h>
#include <units/dimensions/current.h>
namespace units {
struct electric_charge : derived_dimension<electric_charge, exp<time, 1>, exp<current, 1>> {};
template<typename T>
concept ElectricCharge = QuantityOf<T, electric_charge>;
struct coulomb : named_coherent_derived_unit<coulomb, electric_charge, "C", si_prefix> {};
inline namespace literals {
// C
constexpr auto operator""C(unsigned long long l) { return quantity<coulomb, std::int64_t>(l); }
constexpr auto operator""C(long double l) { return quantity<coulomb, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,67 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/si_prefixes.h>
#include <units/dimensions/force.h>
#include <units/dimensions/pressure.h>
namespace units {
struct energy : derived_dimension<energy, exp<force, 1>, exp<length, 1>> {};
template<typename T>
concept Energy = QuantityOf<T, energy>;
struct joule : named_coherent_derived_unit<joule, energy, "J", si_prefix> {};
struct millijoule : prefixed_derived_unit<millijoule, milli, joule> {};
struct kilojoule : prefixed_derived_unit<kilojoule, kilo, joule> {};
struct megajoule : prefixed_derived_unit<megajoule, mega, joule> {};
struct gigajoule : prefixed_derived_unit<gigajoule, giga, joule> {};
inline namespace literals {
// J
constexpr auto operator""_J(unsigned long long l) { return quantity<joule, std::int64_t>(l); }
constexpr auto operator""_J(long double l) { return quantity<joule, long double>(l); }
// mJ
constexpr auto operator""mJ(unsigned long long l) { return quantity<millijoule, std::int64_t>(l); }
constexpr auto operator""mJ(long double l) { return quantity<millijoule, long double>(l); }
// kJ
constexpr auto operator""kJ(unsigned long long l) { return quantity<kilojoule, std::int64_t>(l); }
constexpr auto operator""kJ(long double l) { return quantity<kilojoule, long double>(l); }
// MJ
constexpr auto operator""MJ(unsigned long long l) { return quantity<megajoule, std::int64_t>(l); }
constexpr auto operator""MJ(long double l) { return quantity<megajoule, long double>(l); }
// GJ
constexpr auto operator""GJ(unsigned long long l) { return quantity<gigajoule, std::int64_t>(l); }
constexpr auto operator""GJ(long double l) { return quantity<gigajoule, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,46 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/mass.h>
#include <units/dimensions/acceleration.h>
namespace units {
struct force : derived_dimension<force, exp<mass, 1>, exp<acceleration, 1>> {};
template<typename T>
concept Force = QuantityOf<T, force>;
struct newton : named_coherent_derived_unit<newton, force, "N", si_prefix> {};
inline namespace literals {
// N
constexpr auto operator""N(unsigned long long l) { return quantity<newton, std::int64_t>(l); }
constexpr auto operator""N(long double l) { return quantity<newton, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,71 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/si_prefixes.h>
#include <units/dimensions/time.h>
namespace units {
struct frequency : derived_dimension<frequency, exp<time, -1>> {};
template<typename T>
concept Frequency = QuantityOf<T, frequency>;
struct hertz : named_coherent_derived_unit<hertz, frequency, "Hz", si_prefix> {};
struct millihertz : prefixed_derived_unit<millihertz, milli, hertz> {};
struct kilohertz : prefixed_derived_unit<kilohertz, kilo, hertz> {};
struct megahertz : prefixed_derived_unit<megahertz, mega, hertz> {};
struct gigahertz : prefixed_derived_unit<gigahertz, giga, hertz> {};
struct terahertz : prefixed_derived_unit<terahertz, tera, hertz> {};
inline namespace literals {
// Hz
constexpr auto operator""Hz(unsigned long long l) { return quantity<hertz, std::int64_t>(l); }
constexpr auto operator""Hz(long double l) { return quantity<hertz, long double>(l); }
// mHz
constexpr auto operator""mHz(unsigned long long l) { return quantity<millihertz, std::int64_t>(l); }
constexpr auto operator""mHz(long double l) { return quantity<millihertz, long double>(l); }
// kHz
constexpr auto operator""kHz(unsigned long long l) { return quantity<kilohertz, std::int64_t>(l); }
constexpr auto operator""kHz(long double l) { return quantity<kilohertz, long double>(l); }
// MHz
constexpr auto operator""MHz(unsigned long long l) { return quantity<megahertz, std::int64_t>(l); }
constexpr auto operator""MHz(long double l) { return quantity<megahertz, long double>(l); }
// GHz
constexpr auto operator""GHz(unsigned long long l) { return quantity<gigahertz, std::int64_t>(l); }
constexpr auto operator""GHz(long double l) { return quantity<gigahertz, long double>(l); }
// THz
constexpr auto operator""THz(unsigned long long l) { return quantity<terahertz, std::int64_t>(l); }
constexpr auto operator""THz(long double l) { return quantity<terahertz, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,88 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/si_prefixes.h>
#include <units/quantity.h>
namespace units {
struct length : derived_dimension<length, exp<base_dim_length, 1>> {};
template<typename T>
concept Length = QuantityOf<T, length>;
// SI units
struct metre : named_coherent_derived_unit<metre, length, "m", si_prefix> {};
struct millimetre : prefixed_derived_unit<millimetre, milli, metre> {};
struct centimetre : prefixed_derived_unit<centimetre, centi, metre> {};
struct kilometre : prefixed_derived_unit<kilometre, kilo, metre> {};
inline namespace literals {
// m
constexpr auto operator""m(unsigned long long l) { return quantity<metre, std::int64_t>(l); }
constexpr auto operator""m(long double l) { return quantity<metre, long double>(l); }
// mm
constexpr auto operator""mm(unsigned long long l) { return quantity<millimetre, std::int64_t>(l); }
constexpr auto operator""mm(long double l) { return quantity<millimetre, long double>(l); }
// cm
constexpr auto operator""cm(unsigned long long l) { return quantity<centimetre, std::int64_t>(l); }
constexpr auto operator""cm(long double l) { return quantity<centimetre, long double>(l); }
// km
constexpr auto operator""km(unsigned long long l) { return quantity<kilometre, std::int64_t>(l); }
constexpr auto operator""km(long double l) { return quantity<kilometre, long double>(l); }
} // namespace literals
// US customary units
struct yard : named_scaled_derived_unit<yard, length, "yd", ratio<9'144, 10'000>> {};
struct foot : named_scaled_derived_unit<foot, length, "ft", ratio_divide<yard::ratio, ratio<3>>> {};
struct inch : named_scaled_derived_unit<inch, length, "in", ratio_divide<foot::ratio, ratio<12>>> {};
struct mile : named_scaled_derived_unit<mile, length, "mi", ratio_multiply<ratio<1'760>, yard::ratio>> {};
inline namespace literals {
// yd
constexpr auto operator""yd(unsigned long long l) { return quantity<yard, std::int64_t>(l); }
constexpr auto operator""yd(long double l) { return quantity<yard, long double>(l); }
// ft
constexpr auto operator""ft(unsigned long long l) { return quantity<foot, std::int64_t>(l); }
constexpr auto operator""ft(long double l) { return quantity<foot, long double>(l); }
// in
constexpr auto operator""in(unsigned long long l) { return quantity<inch, std::int64_t>(l); }
constexpr auto operator""in(long double l) { return quantity<inch, long double>(l); }
// mi
constexpr auto operator""mi(unsigned long long l) { return quantity<mile, std::int64_t>(l); }
constexpr auto operator""mi(long double l) { return quantity<mile, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,66 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/si_prefixes.h>
#include <units/dimensions/energy.h>
namespace units {
struct power : derived_dimension<power, exp<energy, 1>, exp<time, -1>> {};
template<typename T>
concept Power = QuantityOf<T, power>;
struct watt : named_coherent_derived_unit<watt, power, "W", si_prefix> {};
struct milliwatt : prefixed_derived_unit<milliwatt, milli, watt> {};
struct kilowatt : prefixed_derived_unit<kilowatt, kilo, watt> {};
struct megawatt : prefixed_derived_unit<megawatt, mega, watt> {};
struct gigawatt : prefixed_derived_unit<gigawatt, giga, watt> {};
inline namespace literals {
// W
constexpr auto operator""W(unsigned long long l) { return quantity<watt, std::int64_t>(l); }
constexpr auto operator""_W(long double l) { return quantity<watt, long double>(l); }
// mW
constexpr auto operator""mW(unsigned long long l) { return quantity<milliwatt, std::int64_t>(l); }
constexpr auto operator""mW(long double l) { return quantity<milliwatt, long double>(l); }
// kW
constexpr auto operator""kW(unsigned long long l) { return quantity<kilowatt, std::int64_t>(l); }
constexpr auto operator""kW(long double l) { return quantity<kilowatt, long double>(l); }
// MW
constexpr auto operator""MW(unsigned long long l) { return quantity<megawatt, std::int64_t>(l); }
constexpr auto operator""MW(long double l) { return quantity<megawatt, long double>(l); }
// GW
constexpr auto operator""GW(unsigned long long l) { return quantity<gigawatt, std::int64_t>(l); }
constexpr auto operator""GW(long double l) { return quantity<gigawatt, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,46 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/force.h>
#include <units/dimensions/area.h>
namespace units {
struct pressure : derived_dimension<pressure, exp<force, 1>, exp<area, -1>> {};
template<typename T>
concept Pressure = QuantityOf<T, pressure>;
struct pascal : named_coherent_derived_unit<pascal, pressure, "Pa", si_prefix> {};
inline namespace literals {
// Pa
constexpr auto operator""Pa(unsigned long long l) { return quantity<pascal, std::int64_t>(l); }
constexpr auto operator""Pa(long double l) { return quantity<pascal, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,52 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/unit.h>
#include <units/format.h>
namespace units {
// prefix tags
struct si_prefix : prefix_type {};
// SI prefixes
struct atto : prefix<atto, si_prefix, ratio<1, std::atto::den>, "a"> {};
struct femto : prefix<femto, si_prefix, ratio<1, std::femto::den>, "f"> {};
struct pico : prefix<pico, si_prefix, ratio<1, std::pico::den>, "p"> {};
struct nano : prefix<nano, si_prefix, ratio<1, std::nano::den>, "n"> {};
struct micro : prefix<micro, si_prefix, ratio<1, std::micro::den>, "\u00b5"> {};
struct milli : prefix<milli, si_prefix, ratio<1, std::milli::den>, "m"> {};
struct centi : prefix<centi, si_prefix, ratio<1, std::centi::den>, "c"> {};
struct deci : prefix<deci, si_prefix, ratio<1, std::deci::den>, "d"> {};
struct deca : prefix<deca, si_prefix, ratio<std::deca::num>, "da"> {};
struct hecto : prefix<hecto, si_prefix, ratio<std::hecto::num>, "h"> {};
struct kilo : prefix<kilo, si_prefix, ratio<std::kilo::num>, "k"> {};
struct mega : prefix<mega, si_prefix, ratio<std::mega::num>, "M"> {};
struct giga : prefix<giga, si_prefix, ratio<std::giga::num>, "G"> {};
struct tera : prefix<tera, si_prefix, ratio<std::tera::num>, "T"> {};
struct peta : prefix<peta, si_prefix, ratio<std::peta::num>, "P"> {};
struct exa : prefix<exa, si_prefix, ratio<std::exa::num>, "E"> {};
}

View File

@@ -1,45 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/force.h>
namespace units {
struct surface_tension : derived_dimension<surface_tension, exp<force, 1>, exp<length, -1>> {};
template<typename T>
concept SurfaceTension = QuantityOf<T, surface_tension>;
struct newton_per_metre : coherent_derived_unit<newton_per_metre, surface_tension> {};
inline namespace literals {
// Nm
constexpr auto operator""Npm(unsigned long long l) { return quantity<newton_per_metre, std::int64_t>(l); }
constexpr auto operator""Npm(long double l) { return quantity<newton_per_metre, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,71 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/si_prefixes.h>
#include <units/quantity.h>
namespace units {
struct time : derived_dimension<time, exp<base_dim_time, 1>> {};
template<typename T>
concept Time = QuantityOf<T, time>;
struct second : named_coherent_derived_unit<second, time, "s", si_prefix> {};
struct nanosecond : prefixed_derived_unit<nanosecond, nano, second> {};
struct microsecond : prefixed_derived_unit<microsecond, micro, second> {};
struct millisecond : prefixed_derived_unit<millisecond, milli, second> {};
struct minute : named_scaled_derived_unit<minute, time, "min", ratio<60>> {};
struct hour : named_scaled_derived_unit<hour, time, "h", ratio<3600>> {};
inline namespace literals {
// ns
constexpr auto operator""ns(unsigned long long l) { return quantity<nanosecond, std::int64_t>(l); }
constexpr auto operator""ns(long double l) { return quantity<nanosecond, long double>(l); }
// us
constexpr auto operator""us(unsigned long long l) { return quantity<microsecond, std::int64_t>(l); }
constexpr auto operator""us(long double l) { return quantity<microsecond, long double>(l); }
// ms
constexpr auto operator""ms(unsigned long long l) { return quantity<millisecond, std::int64_t>(l); }
constexpr auto operator""ms(long double l) { return quantity<millisecond, long double>(l); }
// s
constexpr auto operator""s(unsigned long long l) { return quantity<second, std::int64_t>(l); }
constexpr auto operator""s(long double l) { return quantity<second, long double>(l); }
// min
constexpr auto operator""min(unsigned long long l) { return quantity<minute, std::int64_t>(l); }
constexpr auto operator""min(long double l) { return quantity<minute, long double>(l); }
// h
constexpr auto operator""h(unsigned long long l) { return quantity<hour, std::int64_t>(l); }
constexpr auto operator""h(long double l) { return quantity<hour, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,55 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/length.h>
#include <units/dimensions/time.h>
namespace units {
struct velocity : derived_dimension<velocity, exp<length, 1>, exp<time, -1>> {};
template<typename T>
concept Velocity = QuantityOf<T, velocity>;
struct metre_per_second : coherent_derived_unit<metre_per_second, velocity> {};
struct kilometre_per_hour : deduced_derived_unit<kilometre_per_hour, velocity, kilometre, hour> {};
struct mile_per_hour : deduced_derived_unit<mile_per_hour, velocity, mile, hour> {};
inline namespace literals {
// mps
constexpr auto operator""mps(unsigned long long l) { return quantity<metre_per_second, std::int64_t>(l); }
constexpr auto operator""mps(long double l) { return quantity<metre_per_second, long double>(l); }
// kmph
constexpr auto operator""kmph(unsigned long long l) { return quantity<kilometre_per_hour, std::int64_t>(l); }
constexpr auto operator""kmph(long double l) { return quantity<kilometre_per_hour, long double>(l); }
// mph
constexpr auto operator""mph(unsigned long long l) { return quantity<mile_per_hour, std::int64_t>(l); }
constexpr auto operator""mph(long double l) { return quantity<mile_per_hour, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,48 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/power.h>
#include <units/dimensions/current.h>
#include <units/dimensions/energy.h>
#include <units/dimensions/electric_charge.h>
namespace units {
struct voltage : derived_dimension<voltage, exp<power, 1>, exp<current, -1>> {};
template<typename T>
concept Voltage = QuantityOf<T, voltage>;
struct volt : named_coherent_derived_unit<volt, voltage, "V", si_prefix> {};
inline namespace literals {
// V
constexpr auto operator""V(unsigned long long l) { return quantity<volt, std::int64_t>(l); }
constexpr auto operator""V(long double l) { return quantity<volt, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,64 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/length.h>
namespace units {
struct volume : derived_dimension<volume, exp<length, 3>> {};
template<typename T>
concept Volume = QuantityOf<T, volume>;
struct cubic_metre : coherent_derived_unit<cubic_metre, volume> {};
struct cubic_millimetre : deduced_derived_unit<cubic_millimetre, volume, millimetre> {};
struct cubic_centimetre : deduced_derived_unit<cubic_centimetre, volume, centimetre> {};
struct cubic_kilometre : deduced_derived_unit<cubic_kilometre, volume, kilometre> {};
struct cubic_foot : deduced_derived_unit<cubic_foot, volume, foot> {};
inline namespace literals {
// cub_mm
constexpr auto operator""cub_mm(unsigned long long l) { return quantity<cubic_millimetre, std::int64_t>(l); }
constexpr auto operator""cub_mm(long double l) { return quantity<cubic_millimetre, long double>(l); }
// cub_cm
constexpr auto operator""cub_cm(unsigned long long l) { return quantity<cubic_centimetre, std::int64_t>(l); }
constexpr auto operator""cub_cm(long double l) { return quantity<cubic_centimetre, long double>(l); }
// cub_m
constexpr auto operator""cub_m(unsigned long long l) { return quantity<cubic_metre, std::int64_t>(l); }
constexpr auto operator""cub_m(long double l) { return quantity<cubic_metre, long double>(l); }
// cub_km
constexpr auto operator""cub_km(unsigned long long l) { return quantity<cubic_kilometre, std::int64_t>(l); }
constexpr auto operator""cub_km(long double l) { return quantity<cubic_kilometre, long double>(l); }
// cub_ft
constexpr auto operator""cub_ft(unsigned long long l) { return quantity<cubic_foot, std::int64_t>(l); }
constexpr auto operator""cub_ft(long double l) { return quantity<cubic_foot, long double>(l); }
} // namespace literals
} // namespace units

87
src/include/units/exp.h Normal file
View File

@@ -0,0 +1,87 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/base_dimension.h>
#include <units/ratio.h>
namespace units {
/**
* @brief A power of factor corresponding to the dimension of a quantity
*
* @tparam Dim component dimension of a derived quantity
* @tparam Num numinator of the factor
* @tparam Den denominator of the factor
*/
template<Dimension Dim, int Num, int Den = 1>
struct exp {
using dimension = Dim;
static constexpr int num = Num;
static constexpr int den = Den;
};
// is_exp
namespace detail {
template<typename Dim, int Num, int Den>
inline constexpr bool is_exp<exp<Dim, Num, Den>> = true;
} // namespace detail
// exp_less
template<Exponent E1, Exponent E2>
requires BaseDimension<typename E1::dimension> && BaseDimension<typename E2::dimension>
struct exp_less : base_dimension_less<typename E1::dimension, typename E2::dimension> {};
// exp_invert
namespace detail {
template<typename Dim, int Num, int Den>
constexpr exp<Dim, -Num, Den> exp_invert_impl(exp<Dim, Num, Den>);
} // namespace detail
template<Exponent E>
using exp_invert = decltype(detail::exp_invert_impl(E()));
// exp_multiply
namespace detail {
template<Exponent E, int Num, int Den>
struct exp_multiply_impl {
using r1 = ratio<E::num, E::den>;
using r2 = ratio<Num, Den>;
using r = ratio_multiply<r1, r2>;
using type = exp<typename E::dimension, r::num, r::den>;
};
} // namespace detail
template<Exponent E, int Num, int Den>
using exp_multiply = detail::exp_multiply_impl<E, Num, Den>::type;
template<Exponent... Es>
struct exp_list {};
} // namespace units

View File

@@ -22,7 +22,7 @@
#pragma once
#include <units/bits/customization_points.h>
#include <units/customization_points.h>
#include <units/quantity.h>
#include <fmt/format.h>
#include <string_view>
@@ -116,20 +116,20 @@ namespace units {
return format_to(out, treat_as_floating_point<Rep> ? "{:" + sign_text + "g}" : "{:" + sign_text + "}", val);
}
template<typename Unit, typename OutputIt>
template<typename Dimension, typename Unit, typename OutputIt>
inline static OutputIt format_units_quantity_unit(OutputIt out)
{
return format_to(out, "{}", unit_text<Unit>().c_str());
return format_to(out, "{}", unit_text<Dimension, Unit>().c_str());
}
template<typename OutputIt, typename Unit, typename Rep>
template<typename OutputIt, typename Dimension, typename Unit, typename Rep>
struct units_formatter {
OutputIt out;
Rep val;
fmt::sign_t sign;
int precision;
explicit units_formatter(OutputIt o, quantity<Unit, Rep> q, fmt::sign_t s, int prec):
explicit units_formatter(OutputIt o, quantity<Dimension, Unit, Rep> q, fmt::sign_t s, int prec):
out(o), val(q.count()), sign(s), precision(prec)
{
}
@@ -147,7 +147,7 @@ namespace units {
void on_quantity_unit()
{
out = format_units_quantity_unit<Unit>(out);
out = format_units_quantity_unit<Dimension, Unit>(out);
}
};
@@ -155,11 +155,11 @@ namespace units {
} // namespace units
template<typename Unit, typename Rep, typename CharT>
struct fmt::formatter<units::quantity<Unit, Rep>, CharT> {
template<typename Dimension, typename Unit, typename Rep, typename CharT>
struct fmt::formatter<units::quantity<Dimension, Unit, Rep>, CharT> {
private:
using quantity = units::quantity<Unit, Rep>;
using iterator = fmt::basic_parse_context<CharT>::iterator;
using quantity = units::quantity<Dimension, Unit, Rep>;
using iterator = fmt::basic_format_parse_context<CharT>::iterator;
using arg_ref_type = fmt::internal::arg_ref<CharT>;
fmt::basic_format_specs<CharT> specs;
@@ -172,7 +172,7 @@ private:
struct spec_handler {
formatter& f;
fmt::basic_parse_context<CharT>& context;
fmt::basic_format_parse_context<CharT>& context;
fmt::basic_string_view<CharT> format_str;
template<typename Id>
@@ -185,8 +185,7 @@ private:
constexpr arg_ref_type make_arg_ref(fmt::basic_string_view<CharT> arg_id)
{
context.check_arg_id(arg_id);
const auto str_val = fmt::internal::string_view_metadata(format_str, arg_id);
return arg_ref_type(str_val);
return arg_ref_type(arg_id);
}
constexpr arg_ref_type make_arg_ref(fmt::internal::auto_id)
@@ -226,7 +225,7 @@ private:
iterator end;
};
constexpr parse_range do_parse(fmt::basic_parse_context<CharT>& ctx)
constexpr parse_range do_parse(fmt::basic_format_parse_context<CharT>& ctx)
{
auto begin = ctx.begin(), end = ctx.end();
if(begin == end || *begin == '}')
@@ -285,7 +284,7 @@ private:
}
public:
constexpr auto parse(fmt::basic_parse_context<CharT>& ctx)
constexpr auto parse(fmt::basic_format_parse_context<CharT>& ctx)
{
auto range = do_parse(ctx);
format_str = fmt::basic_string_view<CharT>(&*range.begin, fmt::internal::to_unsigned(range.end - range.begin));
@@ -293,7 +292,7 @@ public:
}
template<typename FormatContext>
auto format(const units::quantity<Unit, Rep>& q, FormatContext& ctx)
auto format(const units::quantity<Dimension, Unit, Rep>& q, FormatContext& ctx)
{
auto begin = format_str.begin(), end = format_str.end();
@@ -302,15 +301,15 @@ public:
auto out = std::back_inserter(buf);
// process dynamic width and precision
fmt::internal::handle_dynamic_spec<fmt::internal::width_checker>(specs.width, width_ref, ctx, format_str.begin());
fmt::internal::handle_dynamic_spec<fmt::internal::precision_checker>(precision, precision_ref, ctx, format_str.begin());
fmt::internal::handle_dynamic_spec<fmt::internal::width_checker>(specs.width, width_ref, ctx);
fmt::internal::handle_dynamic_spec<fmt::internal::precision_checker>(precision, precision_ref, ctx);
// deal with quantity content
if(begin == end || *begin == '}') {
// default format should print value followed by the unit separeted with 1 space
out = units::detail::format_units_quantity_value(out, q.count(), specs.sign, precision);
*out++ = CharT(' ');
units::detail::format_units_quantity_unit<Unit>(out);
units::detail::format_units_quantity_unit<Dimension, Unit>(out);
}
else {
// user provided format

View File

@@ -27,27 +27,29 @@
namespace units {
template<std::size_t N, typename U, typename Rep>
requires N == 0
inline Rep AUTO pow(const quantity<U, Rep>&) noexcept
template<std::size_t N, typename D, typename U, typename Rep>
requires (N == 0)
inline Rep pow(const quantity<D, U, Rep>&) noexcept
{
return 1;
}
template<std::size_t N, typename U, typename Rep>
inline Quantity AUTO pow(const quantity<U, Rep>& q) noexcept
template<std::size_t N, typename D, typename U, typename Rep>
inline Quantity AUTO pow(const quantity<D, U, Rep>& q) noexcept
{
using dim = dimension_pow<typename U::dimension, N>;
using r = ratio_pow<typename U::ratio, N>;
return quantity<downcast<unit<dim, r>>, Rep>(static_cast<Rep>(std::pow(q.count(), N)));
using dim = dimension_pow<D, N>;
using ratio = ratio_pow<typename U::ratio, N>;
using unit = downcast_unit<dim, ratio>;
return quantity<dim, unit, Rep>(static_cast<Rep>(std::pow(q.count(), N)));
}
template<typename U, typename Rep>
inline Quantity AUTO sqrt(const quantity<U, Rep>& q) noexcept
template<typename D, typename U, typename Rep>
inline Quantity AUTO sqrt(const quantity<D, U, Rep>& q) noexcept
{
using dim = dimension_sqrt<typename U::dimension>;
using r = ratio_sqrt<typename U::ratio>;
return quantity<downcast<unit<dim, r>>, Rep>(static_cast<Rep>(std::sqrt(q.count())));
using dim = dimension_sqrt<D>;
using ratio = ratio_sqrt<typename U::ratio>;
using unit = downcast_unit<dim, ratio>;
return quantity<dim, unit, Rep>(static_cast<Rep>(std::sqrt(q.count())));
}
} // namespace units

View File

@@ -0,0 +1,45 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/cgs/velocity.h>
#include <units/quantity.h>
namespace units::cgs {
struct gal : named_unit<gal, "Gal", si::prefix> {};
struct dim_acceleration : physical::dim_acceleration<dim_acceleration, gal, dim_length, dim_time> {};
template<Unit U, Scalar Rep = double>
using acceleration = quantity<dim_acceleration, U, Rep>;
inline namespace literals {
// Gal
constexpr auto operator""Gal(unsigned long long l) { return acceleration<gal, std::int64_t>(l); }
constexpr auto operator""Gal(long double l) { return acceleration<gal, long double>(l); }
} // namespace literals
} // namespace units::cgs

View File

@@ -0,0 +1,47 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/cgs/length.h>
#include <units/physical/si/area.h>
#include <units/quantity.h>
namespace units::cgs {
using si::square_centimetre;
struct dim_area : physical::dim_area<dim_area, square_centimetre, dim_length> {};
template<Unit U, Scalar Rep = double>
using area = quantity<dim_area, U, Rep>;
inline namespace literals {
// sq_cm
constexpr auto operator"" sq_cm(unsigned long long l) { return area<square_centimetre, std::int64_t>(l); }
constexpr auto operator"" sq_cm(long double l) { return area<square_centimetre, long double>(l); }
}
} // namespace units::cgs

View File

@@ -0,0 +1,47 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/cgs/force.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::cgs {
struct erg : named_unit<erg, "erg", si::prefix> {};
struct dim_energy : physical::dim_energy<dim_energy, erg, dim_force, dim_length> {};
template<Unit U, Scalar Rep = double>
using energy = quantity<dim_energy, U, Rep>;
inline namespace literals {
// erg
constexpr auto operator""_erg(unsigned long long l) { return energy<erg, std::int64_t>(l); }
constexpr auto operator""_erg(long double l) { return energy<erg, long double>(l); }
} // namespace literals
} // namespace units::cgs

View File

@@ -0,0 +1,48 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/cgs/acceleration.h>
#include <units/physical/cgs/mass.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::cgs {
struct dyne : named_unit<dyne, "dyn", si::prefix> {};
struct dim_force : physical::dim_force<dim_force, dyne, dim_mass, dim_acceleration> {};
template<Unit U, Scalar Rep = double>
using force = quantity<dim_force, U, Rep>;
inline namespace literals {
// dyn
constexpr auto operator""dyn(unsigned long long l) { return force<dyne, std::int64_t>(l); }
constexpr auto operator""dyn(long double l) { return force<dyne, long double>(l); }
} // namespace literals
} // namespace units::cgs

View File

@@ -22,24 +22,25 @@
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/physical/dimensions.h>
#include <units/physical/si/length.h>
#include <units/quantity.h>
namespace units {
namespace units::cgs {
struct current : derived_dimension<current, exp<base_dim_current, 1>> {};
using si::centimetre;
template<typename T>
concept Current = QuantityOf<T, current>;
struct dim_length : physical::dim_length<centimetre> {};
struct ampere : named_coherent_derived_unit<ampere, current, "A", si_prefix> {};
template<Unit U, Scalar Rep = double>
using length = quantity<dim_length, U, Rep>;
inline namespace literals {
inline namespace literals {
// A
constexpr auto operator""A(unsigned long long l) { return quantity<ampere, std::int64_t>(l); }
constexpr auto operator""A(long double l) { return quantity<ampere, long double>(l); }
// cm
constexpr auto operator"" cm(unsigned long long l) { return length<centimetre, std::int64_t>(l); }
constexpr auto operator"" cm(long double l) { return length<centimetre, long double>(l); }
}
}
} // namespace units
} // namespace units::cgs

View File

@@ -22,16 +22,25 @@
#pragma once
#include <units/dimension.h>
#include <units/physical/dimensions.h>
#include <units/physical/si/mass.h>
#include <units/quantity.h>
namespace units {
namespace units::cgs {
struct base_dim_length : base_dimension<"length", "m"> {};
struct base_dim_mass : base_dimension<"mass", "kg"> {};
struct base_dim_time : base_dimension<"time", "s"> {};
struct base_dim_current : base_dimension<"current", "A"> {};
struct base_dim_temperature : base_dimension<"temperature", "K"> {};
struct base_dim_substance : base_dimension<"substance", "mol"> {};
struct base_dim_luminous_intensity : base_dimension<"luminous intensity", "cd"> {};
using si::gram;
} // namespace units
struct dim_mass : physical::dim_mass<gram> {};
template<Unit U, Scalar Rep = double>
using mass = quantity<dim_mass, U, Rep>;
inline namespace literals {
// g
constexpr auto operator""g(unsigned long long l) { return mass<gram, std::int64_t>(l); }
constexpr auto operator""g(long double l) { return mass<gram, long double>(l); }
}
} // namespace units::cgs

View File

@@ -0,0 +1,47 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/cgs/energy.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::cgs {
struct erg_per_second : unit<erg_per_second> {};
struct dim_power : physical::dim_power<dim_power, erg_per_second, dim_energy, dim_time> {};
template<Unit U, Scalar Rep = double>
using power = quantity<dim_power, U, Rep>;
inline namespace literals {
// ergps
constexpr auto operator""_ergps(unsigned long long l) { return power<erg_per_second, std::int64_t>(l); }
constexpr auto operator""_ergps(long double l) { return power<erg_per_second, long double>(l); }
} // namespace literals
} // namespace units::cgs

View File

@@ -0,0 +1,48 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/cgs/area.h>
#include <units/physical/cgs/force.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::cgs {
struct barye : named_unit<barye, "Ba", si::prefix> {};
struct dim_pressure : physical::dim_pressure<dim_pressure, barye, dim_force, dim_area> {};
template<Unit U, Scalar Rep = double>
using pressure = quantity<dim_pressure, U, Rep>;
inline namespace literals {
// Ba
constexpr auto operator""Ba(unsigned long long l) { return pressure<barye, std::int64_t>(l); }
constexpr auto operator""Ba(long double l) { return pressure<barye, long double>(l); }
} // namespace literals
} // namespace units::cgs

View File

@@ -22,27 +22,21 @@
#pragma once
#include <type_traits>
#include <units/physical/dimensions.h>
#include <units/physical/si/time.h>
#include <units/quantity.h>
namespace units {
namespace units::cgs {
namespace detail {
using si::second;
template<bool>
struct conditional_impl {
template<typename T, typename F>
using type = F;
};
using si::dim_time;
using si::time;
template<>
struct conditional_impl<true> {
template<typename T, typename F>
using type = T;
};
inline namespace literals {
}
template<bool B, typename T, typename F>
using conditional = detail::conditional_impl<B>::template type<T, F>;
using si::literals::operator"" s;
}
} // namespace units::cgs

View File

@@ -0,0 +1,46 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/cgs/length.h>
#include <units/physical/cgs/time.h>
#include <units/quantity.h>
namespace units::cgs {
struct centimetre_per_second : unit<centimetre_per_second> {};
struct dim_velocity : physical::dim_velocity<dim_velocity, centimetre_per_second, dim_length, dim_time> {};
template<Unit U, Scalar Rep = double>
using velocity = quantity<dim_velocity, U, Rep>;
inline namespace literals {
// cmps
constexpr auto operator"" cmps(unsigned long long l) { return velocity<centimetre_per_second, std::int64_t>(l); }
constexpr auto operator"" cmps(long double l) { return velocity<centimetre_per_second, long double>(l); }
} // namespace literals
} // namespace units::cgs

View File

@@ -0,0 +1,166 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/base_dimension.h>
#include <units/bits/external/type_traits.h>
#include <units/quantity.h>
#include <units/unit.h>
namespace units {
namespace physical {
template<typename Dim, template<typename...> typename DimTemplate>
concept DimensionOf = (Dimension<Dim> || BaseDimension<Dim>) && is_derived_from_instantiation<Dim, DimTemplate>;
template<typename Q, template<typename...> typename DimTemplate>
concept QuantityOf = Quantity<Q> && is_derived_from_instantiation<typename Q::dimension, DimTemplate>;
// ------------------------ base dimensions -----------------------------
template<Unit U>
struct dim_length : base_dimension<"L", U> {};
template<Unit U>
struct dim_mass : base_dimension<"M", U> {};
template<Unit U>
struct dim_time : base_dimension<"T", U> {};
template<Unit U>
struct dim_electric_current : base_dimension<"I", U> {};
template<Unit U>
struct dim_thermodynamic_temperature : base_dimension<"Θ", U> {};
template<Unit U>
struct dim_substance : base_dimension<"N", U> {};
template<Unit U>
struct dim_luminous_intensity : base_dimension<"J", U> {};
// ------------------------ derived dimensions -----------------------------
template<typename Child, Unit U, DimensionOf<dim_time> T>
struct dim_frequency : derived_dimension<Child, U, exp<T, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_length> L>
struct dim_area : derived_dimension<Child, U, exp<L, 2>> {};
template<typename Child, Unit U, DimensionOf<dim_length> L>
struct dim_volume : derived_dimension<Child, U, exp<L, 3>> {};
template<typename Child, Unit U, DimensionOf<dim_length> L, DimensionOf<dim_time> T>
struct dim_velocity : derived_dimension<Child, U, exp<L, 1>, exp<T, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_length> L, DimensionOf<dim_time> T>
struct dim_acceleration : derived_dimension<Child, U, exp<L, 1>, exp<T, -2>> {};
template<typename Child, Unit U, DimensionOf<dim_mass> M, DimensionOf<dim_acceleration> A>
struct dim_force : derived_dimension<Child, U, exp<M, 1>, exp<A, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_length> L>
struct dim_energy : derived_dimension<Child, U, exp<F, 1>, exp<L, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_time> T>
struct dim_power : derived_dimension<Child, U, exp<E, 1>, exp<T, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_power> P, DimensionOf<dim_electric_current> C>
struct dim_voltage : derived_dimension<Child, U, exp<P, 1>, exp<C, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_time> T, DimensionOf<dim_electric_current> C>
struct dim_electric_charge : derived_dimension<Child, U, exp<T, 1>, exp<C, 1>> {};
template<typename Child, Unit U, DimensionOf<dim_electric_charge> C, DimensionOf<dim_voltage> V>
struct dim_capacitance : derived_dimension<Child, U, exp<C, 1>, exp<V, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_length> L>
struct dim_surface_tension : derived_dimension<Child, U, exp<F, 1>, exp<L, -1>> {};
template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_area> A>
struct dim_pressure : derived_dimension<Child, U, exp<F, 1>, exp<A, -1>> {};
} // namespace physical
template<typename T>
concept Length = physical::QuantityOf<T, physical::dim_length>;
template<typename T>
concept Mass = physical::QuantityOf<T, physical::dim_mass>;
template<typename T>
concept Time = physical::QuantityOf<T, physical::dim_time>;
template<typename T>
concept Current = physical::QuantityOf<T, physical::dim_electric_current>;
template<typename T>
concept Temperature = physical::QuantityOf<T, physical::dim_thermodynamic_temperature>;
template<typename T>
concept Substance = physical::QuantityOf<T, physical::dim_substance>;
template<typename T>
concept LuminousIntensity = physical::QuantityOf<T, physical::dim_luminous_intensity>;
template<typename T>
concept Frequency = physical::QuantityOf<T, physical::dim_frequency>;
template<typename T>
concept Area = physical::QuantityOf<T, physical::dim_area>;
template<typename T>
concept Volume = physical::QuantityOf<T, physical::dim_volume>;
template<typename T>
concept Velocity = physical::QuantityOf<T, physical::dim_velocity>;
template<typename T>
concept Acceleration = physical::QuantityOf<T, physical::dim_acceleration>;
template<typename T>
concept Force = physical::QuantityOf<T, physical::dim_force>;
template<typename T>
concept Energy = physical::QuantityOf<T, physical::dim_energy>;
template<typename T>
concept Power = physical::QuantityOf<T, physical::dim_power>;
template<typename T>
concept Voltage = physical::QuantityOf<T, physical::dim_voltage>;
template<typename T>
concept ElectricCharge = physical::QuantityOf<T, physical::dim_electric_charge>;
template<typename T>
concept Capacitance = physical::QuantityOf<T, physical::dim_capacitance>;
template<typename T>
concept SurfaceTension = physical::QuantityOf<T, physical::dim_surface_tension>;
template<typename T>
concept Pressure = physical::QuantityOf<T, physical::dim_pressure>;
} // namespace units

View File

@@ -0,0 +1,45 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/velocity.h>
#include <units/quantity.h>
namespace units::si {
struct metre_per_second_sq : unit<metre_per_second_sq> {};
struct dim_acceleration : physical::dim_acceleration<dim_acceleration, metre_per_second_sq, dim_length, dim_time> {};
template<Unit U, Scalar Rep = double>
using acceleration = quantity<dim_acceleration, U, Rep>;
inline namespace literals {
// mps_sq
constexpr auto operator""mps_sq(unsigned long long l) { return acceleration<metre_per_second_sq, std::int64_t>(l); }
constexpr auto operator""mps_sq(long double l) { return acceleration<metre_per_second_sq, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,66 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/length.h>
#include <units/quantity.h>
namespace units::si {
struct square_metre : unit<square_metre> {};
struct dim_area : physical::dim_area<dim_area, square_metre, dim_length> {};
struct square_millimetre : deduced_unit<square_millimetre, dim_area, millimetre> {};
struct square_centimetre : deduced_unit<square_centimetre, dim_area, centimetre> {};
struct square_kilometre : deduced_unit<square_kilometre, dim_area, kilometre> {};
struct square_foot : deduced_unit<square_foot, dim_area, foot> {};
template<Unit U, Scalar Rep = double>
using area = quantity<dim_area, U, Rep>;
inline namespace literals {
// sq_m
constexpr auto operator"" sq_m(unsigned long long l) { return area<square_metre, std::int64_t>(l); }
constexpr auto operator"" sq_m(long double l) { return area<square_metre, long double>(l); }
// sq_mm
constexpr auto operator"" sq_mm(unsigned long long l) { return area<square_millimetre, std::int64_t>(l); }
constexpr auto operator"" sq_mm(long double l) { return area<square_millimetre, long double>(l); }
// sq_cm
constexpr auto operator"" sq_cm(unsigned long long l) { return area<square_centimetre, std::int64_t>(l); }
constexpr auto operator"" sq_cm(long double l) { return area<square_centimetre, long double>(l); }
// sq_km
constexpr auto operator"" sq_km(unsigned long long l) { return area<square_kilometre, std::int64_t>(l); }
constexpr auto operator"" sq_km(long double l) { return area<square_kilometre, long double>(l); }
// sq_ft
constexpr auto operator"" sq_ft(unsigned long long l) { return area<square_foot, std::int64_t>(l); }
constexpr auto operator"" sq_ft(long double l) { return area<square_foot, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,48 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/electric_charge.h>
#include <units/physical/si/voltage.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::si {
struct farad : named_unit<farad, "F", prefix> {};
struct dim_capacitance : physical::dim_capacitance<dim_capacitance, farad, dim_electric_charge, dim_voltage> {};
template<Unit U, Scalar Rep = double>
using capacitance = quantity<dim_capacitance, U, Rep>;
inline namespace literals {
// F
constexpr auto operator""F(unsigned long long l) { return capacitance<farad, std::int64_t>(l); }
constexpr auto operator""_F(long double l) { return capacitance<farad, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,46 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::si {
struct ampere : named_unit<ampere, "m", prefix> {};
struct dim_electric_current : physical::dim_electric_current<ampere> {};
template<Unit U, Scalar Rep = double>
using current = quantity<dim_electric_current, U, Rep>;
inline namespace literals {
// A
constexpr auto operator""A(unsigned long long l) { return current<ampere, std::int64_t>(l); }
constexpr auto operator""A(long double l) { return current<ampere, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,47 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/current.h>
#include <units/physical/si/time.h>
#include <units/quantity.h>
namespace units::si {
struct coulomb : named_unit<coulomb, "C", prefix> {};
struct dim_electric_charge : physical::dim_electric_charge<dim_electric_charge, coulomb, dim_time, dim_electric_current> {};
template<Unit U, Scalar Rep = double>
using electric_charge = quantity<dim_electric_charge, U, Rep>;
inline namespace literals {
// C
constexpr auto operator""C(unsigned long long l) { return electric_charge<coulomb, std::int64_t>(l); }
constexpr auto operator""C(long double l) { return electric_charge<coulomb, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,67 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/force.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::si {
struct joule : named_unit<joule, "J", prefix> {};
struct millijoule : prefixed_unit<millijoule, milli, joule> {};
struct kilojoule : prefixed_unit<kilojoule, kilo, joule> {};
struct megajoule : prefixed_unit<megajoule, mega, joule> {};
struct gigajoule : prefixed_unit<gigajoule, giga, joule> {};
struct dim_energy : physical::dim_energy<dim_energy, joule, dim_force, dim_length> {};
template<Unit U, Scalar Rep = double>
using energy = quantity<dim_energy, U, Rep>;
inline namespace literals {
// J
constexpr auto operator""_J(unsigned long long l) { return energy<joule, std::int64_t>(l); }
constexpr auto operator""_J(long double l) { return energy<joule, long double>(l); }
// mJ
constexpr auto operator""mJ(unsigned long long l) { return energy<millijoule, std::int64_t>(l); }
constexpr auto operator""mJ(long double l) { return energy<millijoule, long double>(l); }
// kJ
constexpr auto operator""kJ(unsigned long long l) { return energy<kilojoule, std::int64_t>(l); }
constexpr auto operator""kJ(long double l) { return energy<kilojoule, long double>(l); }
// MJ
constexpr auto operator""MJ(unsigned long long l) { return energy<megajoule, std::int64_t>(l); }
constexpr auto operator""MJ(long double l) { return energy<megajoule, long double>(l); }
// GJ
constexpr auto operator""GJ(unsigned long long l) { return energy<gigajoule, std::int64_t>(l); }
constexpr auto operator""GJ(long double l) { return energy<gigajoule, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,48 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/acceleration.h>
#include <units/physical/si/mass.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::si {
struct newton : named_unit<newton, "N", prefix> {};
struct dim_force : physical::dim_force<dim_force, newton, dim_mass, dim_acceleration> {};
template<Unit U, Scalar Rep = double>
using force = quantity<dim_force, U, Rep>;
inline namespace literals {
// N
constexpr auto operator""N(unsigned long long l) { return force<newton, std::int64_t>(l); }
constexpr auto operator""N(long double l) { return force<newton, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,71 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/time.h>
#include <units/quantity.h>
namespace units::si {
struct hertz : named_unit<hertz, "Hz", prefix> {};
struct millihertz : prefixed_unit<millihertz, milli, hertz> {};
struct kilohertz : prefixed_unit<kilohertz, kilo, hertz> {};
struct megahertz : prefixed_unit<megahertz, mega, hertz> {};
struct gigahertz : prefixed_unit<gigahertz, giga, hertz> {};
struct terahertz : prefixed_unit<terahertz, tera, hertz> {};
struct dim_frequency : physical::dim_frequency<dim_frequency, hertz, dim_time> {};
template<Unit U, Scalar Rep = double>
using frequency = quantity<dim_frequency, U, Rep>;
inline namespace literals {
// Hz
constexpr auto operator"" Hz(unsigned long long l) { return frequency<hertz, std::int64_t>(l); }
constexpr auto operator"" Hz(long double l) { return frequency<hertz, long double>(l); }
// mHz
constexpr auto operator"" mHz(unsigned long long l) { return frequency<millihertz, std::int64_t>(l); }
constexpr auto operator"" mHz(long double l) { return frequency<millihertz, long double>(l); }
// kHz
constexpr auto operator"" kHz(unsigned long long l) { return frequency<kilohertz, std::int64_t>(l); }
constexpr auto operator"" kHz(long double l) { return frequency<kilohertz, long double>(l); }
// MHz
constexpr auto operator"" MHz(unsigned long long l) { return frequency<megahertz, std::int64_t>(l); }
constexpr auto operator"" MHz(long double l) { return frequency<megahertz, long double>(l); }
// GHz
constexpr auto operator"" GHz(unsigned long long l) { return frequency<gigahertz, std::int64_t>(l); }
constexpr auto operator"" GHz(long double l) { return frequency<gigahertz, long double>(l); }
// THz
constexpr auto operator"" THz(unsigned long long l) { return frequency<terahertz, std::int64_t>(l); }
constexpr auto operator"" THz(long double l) { return frequency<terahertz, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,87 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::si {
struct metre : named_unit<metre, "m", prefix> {};
struct millimetre : prefixed_unit<millimetre, milli, metre> {};
struct centimetre : prefixed_unit<centimetre, centi, metre> {};
struct kilometre : prefixed_unit<kilometre, kilo, metre> {};
struct dim_length : physical::dim_length<metre> {};
template<Unit U, Scalar Rep = double>
using length = quantity<dim_length, U, Rep>;
inline namespace literals {
// m
constexpr auto operator"" m(unsigned long long l) { return length<metre, std::int64_t>(l); }
constexpr auto operator"" m(long double l) { return length<metre, long double>(l); }
// mm
constexpr auto operator"" mm(unsigned long long l) { return length<millimetre, std::int64_t>(l); }
constexpr auto operator"" mm(long double l) { return length<millimetre, long double>(l); }
// cm
constexpr auto operator"" cm(unsigned long long l) { return length<centimetre, std::int64_t>(l); }
constexpr auto operator"" cm(long double l) { return length<centimetre, long double>(l); }
// km
constexpr auto operator"" km(unsigned long long l) { return length<kilometre, std::int64_t>(l); }
constexpr auto operator"" km(long double l) { return length<kilometre, long double>(l); }
} // namespace literals
// US customary units
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio<9'144, 10'000>, metre> {};
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio<1, 3>, yard> {};
struct inch : named_scaled_unit<inch, "in", no_prefix, ratio<1, 12>, foot> {};
struct mile : named_scaled_unit<mile, "mi", no_prefix, ratio<1'760>, yard> {};
inline namespace literals {
// yd
constexpr auto operator"" yd(unsigned long long l) { return length<yard, std::int64_t>(l); }
constexpr auto operator"" yd(long double l) { return length<yard, long double>(l); }
// ft
constexpr auto operator"" ft(unsigned long long l) { return length<foot, std::int64_t>(l); }
constexpr auto operator"" ft(long double l) { return length<foot, long double>(l); }
// in
constexpr auto operator"" in(unsigned long long l) { return length<inch, std::int64_t>(l); }
constexpr auto operator"" in(long double l) { return length<inch, long double>(l); }
// mi
constexpr auto operator"" mi(unsigned long long l) { return length<mile, std::int64_t>(l); }
constexpr auto operator"" mi(long double l) { return length<mile, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -22,24 +22,25 @@
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/physical/dimensions.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units {
namespace units::si {
struct luminous_intensity : derived_dimension<luminous_intensity, exp<base_dim_luminous_intensity, 1>> {};
struct candela : named_unit<candela, "cd", prefix> {};
template<typename T>
concept LuminousIntensity = QuantityOf<T, luminous_intensity>;
struct dim_luminous_intensity : physical::dim_luminous_intensity<candela> {};
struct candela : named_coherent_derived_unit<candela, luminous_intensity, "cd", si_prefix> {};
template<Unit U, Scalar Rep = double>
using luminous_intensity = quantity<dim_luminous_intensity, U, Rep>;
inline namespace literals {
inline namespace literals {
// cd
constexpr auto operator""cd(unsigned long long l) { return quantity<candela, std::int64_t>(l); }
constexpr auto operator""cd(long double l) { return quantity<candela, long double>(l); }
// cd
constexpr auto operator""cd(unsigned long long l) { return luminous_intensity<candela, std::int64_t>(l); }
constexpr auto operator""cd(long double l) { return luminous_intensity<candela, long double>(l); }
} // namespace literals
} // namespace literals
} // namespace units
} // namespace units::si

View File

@@ -0,0 +1,51 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::si {
struct gram : named_unit<gram, "g", prefix> {};
struct kilogram : prefixed_unit<kilogram, kilo, gram> {};
struct dim_mass : physical::dim_mass<kilogram> {};
template<Unit U, Scalar Rep = double>
using mass = quantity<dim_mass, U, Rep>;
inline namespace literals {
// g
constexpr auto operator""g(unsigned long long l) { return mass<gram, std::int64_t>(l); }
constexpr auto operator""g(long double l) { return mass<gram, long double>(l); }
// kg
constexpr auto operator""kg(unsigned long long l) { return mass<kilogram, std::int64_t>(l); }
constexpr auto operator""kg(long double l) { return mass<kilogram, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,67 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/energy.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::si {
struct watt : named_unit<watt, "W", prefix> {};
struct milliwatt : prefixed_unit<milliwatt, milli, watt> {};
struct kilowatt : prefixed_unit<kilowatt, kilo, watt> {};
struct megawatt : prefixed_unit<megawatt, mega, watt> {};
struct gigawatt : prefixed_unit<gigawatt, giga, watt> {};
struct dim_power : physical::dim_power<dim_power, watt, dim_energy, dim_time> {};
template<Unit U, Scalar Rep = double>
using power = quantity<dim_power, U, Rep>;
inline namespace literals {
// W
constexpr auto operator""W(unsigned long long l) { return power<watt, std::int64_t>(l); }
constexpr auto operator""_W(long double l) { return power<watt, long double>(l); }
// mW
constexpr auto operator""mW(unsigned long long l) { return power<milliwatt, std::int64_t>(l); }
constexpr auto operator""mW(long double l) { return power<milliwatt, long double>(l); }
// kW
constexpr auto operator""kW(unsigned long long l) { return power<kilowatt, std::int64_t>(l); }
constexpr auto operator""kW(long double l) { return power<kilowatt, long double>(l); }
// MW
constexpr auto operator""MW(unsigned long long l) { return power<megawatt, std::int64_t>(l); }
constexpr auto operator""MW(long double l) { return power<megawatt, long double>(l); }
// GW
constexpr auto operator""GW(unsigned long long l) { return power<gigawatt, std::int64_t>(l); }
constexpr auto operator""GW(long double l) { return power<gigawatt, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,51 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/prefix.h>
#include <ratio>
namespace units::si {
struct prefix : prefix_type {};
// TODO Remove dependency on std::ratio
struct atto : units::prefix<atto, prefix, "a", ratio<1, std::atto::den>> {};
struct femto : units::prefix<femto, prefix, "f", ratio<1, std::femto::den>> {};
struct pico : units::prefix<pico, prefix, "p", ratio<1, std::pico::den>> {};
struct nano : units::prefix<nano, prefix, "n", ratio<1, std::nano::den>> {};
struct micro : units::prefix<micro, prefix, "\u00b5", ratio<1, std::micro::den>> {};
struct milli : units::prefix<milli, prefix, "m", ratio<1, std::milli::den>> {};
struct centi : units::prefix<centi, prefix, "c", ratio<1, std::centi::den>> {};
struct deci : units::prefix<deci, prefix, "d", ratio<1, std::deci::den>> {};
struct deca : units::prefix<deca, prefix, "da", ratio<std::deca::num>> {};
struct hecto : units::prefix<hecto, prefix, "h", ratio<std::hecto::num>> {};
struct kilo : units::prefix<kilo, prefix, "k", ratio<std::kilo::num>> {};
struct mega : units::prefix<mega, prefix, "M", ratio<std::mega::num>> {};
struct giga : units::prefix<giga, prefix, "G", ratio<std::giga::num>> {};
struct tera : units::prefix<tera, prefix, "T", ratio<std::tera::num>> {};
struct peta : units::prefix<peta, prefix, "P", ratio<std::peta::num>> {};
struct exa : units::prefix<exa, prefix, "E", ratio<std::exa::num>> {};
} // namespace units::si

View File

@@ -0,0 +1,48 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/area.h>
#include <units/physical/si/force.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::si {
struct pascal : named_unit<pascal, "Pa", prefix> {};
struct dim_pressure : physical::dim_pressure<dim_pressure, pascal, dim_force, dim_area> {};
template<Unit U, Scalar Rep = double>
using pressure = quantity<dim_pressure, U, Rep>;
inline namespace literals {
// Pa
constexpr auto operator""Pa(unsigned long long l) { return pressure<pascal, std::int64_t>(l); }
constexpr auto operator""Pa(long double l) { return pressure<pascal, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -22,24 +22,25 @@
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/physical/dimensions.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units {
namespace units::si {
struct substance : derived_dimension<substance, exp<base_dim_substance, 1>> {};
struct mole : named_unit<metre, "mol", prefix> {};
template<typename T>
concept Substance = QuantityOf<T, substance>;
struct dim_substance : physical::dim_substance<mole> {};
struct mole : named_coherent_derived_unit<mole, substance, "mol", si_prefix> {};
template<Unit U, Scalar Rep = double>
using substance = quantity<dim_substance, U, Rep>;
inline namespace literals {
inline namespace literals {
// mol
constexpr auto operator""mol(unsigned long long l) { return quantity<mole, std::int64_t>(l); }
constexpr auto operator""mol(long double l) { return quantity<mole, long double>(l); }
// mol
constexpr auto operator"" mol(unsigned long long l) { return substance<mole, std::int64_t>(l); }
constexpr auto operator"" mol(long double l) { return substance<mole, long double>(l); }
} // namespace literals
} // namespace literals
} // namespace units
} // namespace units::si

View File

@@ -0,0 +1,46 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/force.h>
#include <units/quantity.h>
namespace units::si {
struct newton_per_metre : unit<newton_per_metre> {};
struct dim_surface_tension : physical::dim_surface_tension<dim_surface_tension, newton_per_metre, dim_force, dim_length> {};
template<Unit U, Scalar Rep = double>
using surface_tension = quantity<dim_surface_tension, U, Rep>;
inline namespace literals {
// Nm
constexpr auto operator""Npm(unsigned long long l) { return surface_tension<newton_per_metre, std::int64_t>(l); }
constexpr auto operator""Npm(long double l) { return surface_tension<newton_per_metre, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -22,24 +22,24 @@
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/physical/dimensions.h>
#include <units/quantity.h>
namespace units {
namespace units::si {
struct temperature : derived_dimension<temperature, exp<base_dim_temperature, 1>> {};
struct kelvin : named_unit<kelvin, "K", no_prefix> {};
template<typename T>
concept ThermodynamicTemperature = QuantityOf<T, temperature>;
struct dim_thermodynamic_temperature : physical::dim_thermodynamic_temperature<kelvin> {};
struct kelvin : named_coherent_derived_unit<kelvin, temperature, "K", no_prefix> {};
template<Unit U, Scalar Rep = double>
using temperature = quantity<dim_thermodynamic_temperature, U, Rep>;
inline namespace literals {
inline namespace literals {
// K
constexpr auto operator""K(unsigned long long l) { return quantity<kelvin, std::int64_t>(l); }
constexpr auto operator""_K(long double l) { return quantity<kelvin, long double>(l); } // TODO: conflicts with gcc GNU extension
// K
constexpr auto operator""K(unsigned long long l) { return temperature<kelvin, std::int64_t>(l); }
constexpr auto operator""_K(long double l) { return temperature<kelvin, long double>(l); } // TODO: conflicts with gcc GNU extension
} // namespace literals
} // namespace literals
} // namespace units
} // namespace units::si

View File

@@ -0,0 +1,71 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::si {
struct second : named_unit<second, "s", prefix> {};
struct nanosecond : prefixed_unit<nanosecond, nano, second> {};
struct microsecond : prefixed_unit<microsecond, micro, second> {};
struct millisecond : prefixed_unit<millisecond, milli, second> {};
struct minute : named_scaled_unit<minute, "min", no_prefix, ratio<60>, second> {};
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio<3600>, second> {};
struct dim_time : physical::dim_time<second> {};
template<Unit U, Scalar Rep = double>
using time = quantity<dim_time, U, Rep>;
inline namespace literals {
// ns
constexpr auto operator""ns(unsigned long long l) { return time<nanosecond, std::int64_t>(l); }
constexpr auto operator""ns(long double l) { return time<nanosecond, long double>(l); }
// us
constexpr auto operator""us(unsigned long long l) { return time<microsecond, std::int64_t>(l); }
constexpr auto operator""us(long double l) { return time<microsecond, long double>(l); }
// ms
constexpr auto operator""ms(unsigned long long l) { return time<millisecond, std::int64_t>(l); }
constexpr auto operator""ms(long double l) { return time<millisecond, long double>(l); }
// s
constexpr auto operator""s(unsigned long long l) { return time<second, std::int64_t>(l); }
constexpr auto operator""s(long double l) { return time<second, long double>(l); }
// min
constexpr auto operator""min(unsigned long long l) { return time<minute, std::int64_t>(l); }
constexpr auto operator""min(long double l) { return time<minute, long double>(l); }
// h
constexpr auto operator""h(unsigned long long l) { return time<hour, std::int64_t>(l); }
constexpr auto operator""h(long double l) { return time<hour, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,57 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/length.h>
#include <units/physical/si/time.h>
#include <units/quantity.h>
namespace units::si {
struct metre_per_second : unit<metre_per_second> {};
struct dim_velocity : physical::dim_velocity<dim_velocity, metre_per_second, dim_length, dim_time> {};
struct kilometre_per_hour : deduced_unit<kilometre_per_hour, dim_velocity, kilometre, hour> {};
struct mile_per_hour : deduced_unit<mile_per_hour, dim_velocity, mile, hour> {};
template<Unit U, Scalar Rep = double>
using velocity = quantity<dim_velocity, U, Rep>;
inline namespace literals {
// mps
constexpr auto operator"" mps(unsigned long long l) { return velocity<metre_per_second, std::int64_t>(l); }
constexpr auto operator"" mps(long double l) { return velocity<metre_per_second, long double>(l); }
// kmph
constexpr auto operator"" kmph(unsigned long long l) { return velocity<kilometre_per_hour, std::int64_t>(l); }
constexpr auto operator"" kmph(long double l) { return velocity<kilometre_per_hour, long double>(l); }
// mph
constexpr auto operator"" mph(unsigned long long l) { return velocity<mile_per_hour, std::int64_t>(l); }
constexpr auto operator"" mph(long double l) { return velocity<mile_per_hour, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,48 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/current.h>
#include <units/physical/si/power.h>
#include <units/physical/si/prefixes.h>
#include <units/quantity.h>
namespace units::si {
struct volt : named_unit<volt, "V", prefix> {};
struct dim_voltage : physical::dim_voltage<dim_voltage, volt, dim_power, dim_electric_current> {};
template<Unit U, Scalar Rep = double>
using voltage = quantity<dim_voltage, U, Rep>;
inline namespace literals {
// V
constexpr auto operator""V(unsigned long long l) { return voltage<volt, std::int64_t>(l); }
constexpr auto operator""V(long double l) { return voltage<volt, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,66 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/length.h>
#include <units/quantity.h>
namespace units::si {
struct cubic_metre : unit<cubic_metre> {};
struct dim_volume : physical::dim_volume<dim_volume, cubic_metre, dim_length> {};
struct cubic_millimetre : deduced_unit<cubic_millimetre, dim_volume, millimetre> {};
struct cubic_centimetre : deduced_unit<cubic_centimetre, dim_volume, centimetre> {};
struct cubic_kilometre : deduced_unit<cubic_kilometre, dim_volume, kilometre> {};
struct cubic_foot : deduced_unit<cubic_foot, dim_volume, foot> {};
template<Unit U, Scalar Rep = double>
using volume = quantity<dim_volume, U, Rep>;
inline namespace literals {
// cub_mm
constexpr auto operator""cub_mm(unsigned long long l) { return volume<cubic_millimetre, std::int64_t>(l); }
constexpr auto operator""cub_mm(long double l) { return volume<cubic_millimetre, long double>(l); }
// cub_cm
constexpr auto operator""cub_cm(unsigned long long l) { return volume<cubic_centimetre, std::int64_t>(l); }
constexpr auto operator""cub_cm(long double l) { return volume<cubic_centimetre, long double>(l); }
// cub_m
constexpr auto operator""cub_m(unsigned long long l) { return volume<cubic_metre, std::int64_t>(l); }
constexpr auto operator""cub_m(long double l) { return volume<cubic_metre, long double>(l); }
// cub_km
constexpr auto operator""cub_km(unsigned long long l) { return volume<cubic_kilometre, std::int64_t>(l); }
constexpr auto operator""cub_km(long double l) { return volume<cubic_kilometre, long double>(l); }
// cub_ft
constexpr auto operator""cub_ft(unsigned long long l) { return volume<cubic_foot, std::int64_t>(l); }
constexpr auto operator""cub_ft(long double l) { return volume<cubic_foot, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -22,49 +22,56 @@
#pragma once
#include <units/bits/downcasting.h>
#include <units/bits/fixed_string.h>
#include <units/bits/external/downcasting.h>
#include <units/bits/external/fixed_string.h>
#include <units/ratio.h>
namespace units {
struct prefix_type {};
/**
* @brief The base for all prefix types
*
* Every prefix type should inherit from this type to satisfy PrefixType concept.
*/
struct prefix_type {};
template<typename T>
concept PrefixType = std::derived_from<T, prefix_type>;
/**
* @brief No prefix possible for the unit
*
* This is a special prefix type tag specifying that the unit can not be scaled with any kind
* of the prefix.
*/
struct no_prefix : prefix_type {};
namespace detail {
namespace detail {
template<PrefixType PT, Ratio R>
struct prefix_base : downcast_base<prefix_base<PT, R>> {
using prefix_type = PT;
using ratio = R;
};
template<PrefixType PT, Ratio R>
struct prefix_base : downcast_base<prefix_base<PT, R>> {
using prefix_type = PT;
using ratio = R;
};
}
} // namespace detail
template<typename Child, PrefixType PT, Ratio R, basic_fixed_string Symbol>
struct prefix : downcast_child<Child, detail::prefix_base<PT, R>> {
static constexpr auto symbol = Symbol;
};
// TODO gcc:92150
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92150
// namespace detail {
// template<typename T>
// inline constexpr bool is_prefix = false;
// template<typename PrefixType, Ratio R, basic_fixed_string Symbol>
// inline constexpr bool is_prefix<prefix<PrefixType, R, Symbol>> = true;
// } // namespace detail
template<typename T>
// concept Prefix = detail::is_prefix<T>;
concept Prefix = true;
struct no_prefix : prefix_type {};
/**
* @brief A prefix used to scale units
*
* Data from a prefix class is used in two cases:
* - when defining a prefixed_unit its ratio is used to scale the reference unit and its
* symbol is used to prepend to the symbol of referenced unit
* - when printing the symbol of a scaled unit that was not predefined by the user but its
* factor matches ratio of a prefix from the specified prefix family, its symbol will be
* prepended to the symbol of the unit
*
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
* @tparam PT a type of prefix family
* @tparam Symbol a text representation of the prefix
* @tparam R factor to be used to scale a unit
*/
template<typename Child, PrefixType PT, basic_fixed_string Symbol, Ratio R>
requires (!std::same_as<PT, no_prefix>)
struct prefix : downcast_child<Child, detail::prefix_base<PT, ratio<R::num, R::den>>> {
static constexpr auto symbol = Symbol;
};
} // namespace units

View File

@@ -22,518 +22,430 @@
#pragma once
#include <units/bits/concepts.h>
#include <units/unit.h>
#include <limits>
#include <units/bits/common_quantity.h>
#include <units/bits/dimension_op.h>
#include <units/bits/unit_text.h>
#include <units/quantity_cast.h>
#if __GNUC__ >= 10
#include <compare>
#endif
#include <ostream>
namespace units {
// is_quantity
namespace detail {
namespace detail {
template<typename T>
inline constexpr bool is_quantity = false;
template<typename From, typename To>
concept safe_convertible = // exposition only
std::convertible_to<From, To> &&
(treat_as_floating_point<To> || (!treat_as_floating_point<From>));
// partial specialization below after the first quantity forward declaration
template<typename Rep, typename UnitFrom, typename UnitTo>
concept safe_divisible = // exposition only
treat_as_floating_point<Rep> ||
ratio_divide<typename UnitFrom::ratio, typename UnitTo::ratio>::den == 1;
} // namespace detail
} // namespace detail
template<typename T>
concept Quantity = detail::is_quantity<T>;
/**
* @brief A quantity
*
* Property of a phenomenon, body, or substance, where the property has a magnitude that can be
* expressed by means of a number and a measurement unit.
*
* @tparam D a dimension of the quantity (can be either a BaseDimension or a DerivedDimension)
* @tparam U a measurement unit of the quantity
* @tparam Rep a type to be used to represent values of a quantity
*/
template<Dimension D, UnitOf<D> U, Scalar Rep = double>
class quantity {
Rep value_;
template<typename T, typename Dim>
concept QuantityOf = Quantity<T> && Dimension<Dim> && same_dim<typename T::dimension, Dim>;
public:
using dimension = D;
using unit = U;
using rep = Rep;
// Scalar
template<typename T>
concept Scalar =
(!Quantity<T>) &&
std::regular<T> &&
std::totally_ordered<T> &&
detail::basic_arithmetic<T>;
quantity() = default;
quantity(const quantity&) = default;
quantity(quantity&&) = default;
template<Unit U, Scalar Rep>
class quantity;
template<Scalar Value>
requires detail::safe_convertible<Value, rep>
constexpr explicit quantity(const Value& v) : value_{static_cast<rep>(v)} {}
namespace detail {
template<Quantity Q2>
requires equivalent_dim<D, typename Q2::dimension> &&
detail::safe_convertible<typename Q2::rep, rep> &&
detail::safe_divisible<rep, typename Q2::unit, unit>
constexpr quantity(const Q2& q) : value_{quantity_cast<quantity>(q).count()} {}
template<typename U, typename Rep>
inline constexpr bool is_quantity<quantity<U, Rep>> = true;
quantity& operator=(const quantity&) = default;
quantity& operator=(quantity&&) = default;
} // namespace detail
[[nodiscard]] constexpr rep count() const noexcept { return value_; }
// common_quantity
namespace detail {
template<typename Q1, typename Q2, typename Rep>
struct common_quantity_impl;
template<typename U, typename Rep1, typename Rep2, typename Rep>
struct common_quantity_impl<quantity<U, Rep1>, quantity<U, Rep2>, Rep> {
using type = quantity<U, Rep>;
};
template<typename U1, typename Rep1, typename U2, typename Rep2, typename Rep>
requires same_dim<typename U1::dimension, typename U2::dimension>
struct common_quantity_impl<quantity<U1, Rep1>, quantity<U2, Rep2>, Rep> {
using type =
quantity<downcast<unit<typename U1::dimension, common_ratio<typename U1::ratio, typename U2::ratio>>>,
Rep>;
};
} // namespace detail
template<Quantity Q1, Quantity Q2, Scalar Rep = std::common_type_t<typename Q1::rep, typename Q2::rep>>
using common_quantity = detail::common_quantity_impl<Q1, Q2, Rep>::type;
// quantity_cast
namespace detail {
template<typename To, typename CRatio, typename CRep, bool NumIsOne = false, bool DenIsOne = false>
struct quantity_cast_impl {
template<typename Q>
static constexpr To cast(const Q& q)
{
if constexpr(treat_as_floating_point<CRep>) {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) *
(static_cast<CRep>(CRatio::num) / static_cast<CRep>(CRatio::den))));
}
else {
return To(
static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num) / static_cast<CRep>(CRatio::den)));
}
}
};
template<typename To, typename CRatio, typename CRep>
struct quantity_cast_impl<To, CRatio, CRep, true, true> {
template<Quantity Q>
static constexpr To cast(const Q& q)
{
return To(static_cast<To::rep>(q.count()));
}
};
template<typename To, typename CRatio, typename CRep>
struct quantity_cast_impl<To, CRatio, CRep, true, false> {
template<Quantity Q>
static constexpr To cast(const Q& q)
{
if constexpr(treat_as_floating_point<CRep>) {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * (CRep{1} / static_cast<CRep>(CRatio::den))));
}
else {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(CRatio::den)));
}
}
};
template<typename To, typename CRatio, typename CRep>
struct quantity_cast_impl<To, CRatio, CRep, false, true> {
template<Quantity Q>
static constexpr To cast(const Q& q)
{
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num)));
}
};
} // namespace detail
template<Quantity To, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<U, Rep>& q)
requires same_dim<typename To::dimension, typename U::dimension> &&
detail::basic_arithmetic<std::common_type_t<typename To::rep, Rep, intmax_t>>
template<typename T = Rep>
[[nodiscard]] static constexpr quantity zero() noexcept
requires requires { quantity_values<T>::zero(); }
// requires requires { quantity_values<Rep>::zero(); } // TODO gated by gcc-9 (fixed in gcc-10)
{
using c_ratio = ratio_divide<typename U::ratio, typename To::unit::ratio>;
using c_rep = std::common_type_t<typename To::rep, Rep, intmax_t>;
using ret_dim = downcast<typename To::unit::dimension>;
using ret_unit = downcast<unit<ret_dim, typename To::unit::ratio>>;
using ret = quantity<ret_unit, typename To::rep>;
using cast = detail::quantity_cast_impl<ret, c_ratio, c_rep, c_ratio::num == 1, c_ratio::den == 1>;
return cast::cast(q);
return quantity(quantity_values<Rep>::zero());
}
template<Unit ToU, Scalar ToRep, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<U, Rep>& q)
requires same_dim<typename ToU::dimension, typename U::dimension> &&
detail::basic_arithmetic<std::common_type_t<ToRep, Rep, intmax_t>>
template<typename T = Rep>
[[nodiscard]] static constexpr quantity one() noexcept
requires requires { quantity_values<T>::one(); }
// requires requires { quantity_values<Rep>::one(); } // TODO gated by gcc-9 (fixed in gcc-10)
{
return quantity_cast<quantity<ToU, ToRep>>(q);
return quantity(quantity_values<Rep>::one());
}
template<Unit ToU, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<U, Rep>& q)
requires same_dim<typename ToU::dimension, typename U::dimension>
template<typename T = Rep>
[[nodiscard]] static constexpr quantity min() noexcept
requires requires { quantity_values<T>::min(); }
// requires requires { quantity_values<Rep>::min(); } // TODO gated by gcc-9 (fixed in gcc-10)
{
return quantity_cast<quantity<ToU, Rep>>(q);
return quantity(quantity_values<Rep>::min());
}
template<Scalar ToRep, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<U, Rep>& q)
requires detail::basic_arithmetic<std::common_type_t<ToRep, Rep, intmax_t>>
template<typename T = Rep>
[[nodiscard]] static constexpr quantity max() noexcept
requires requires { quantity_values<T>::max(); }
// requires requires { quantity_values<Rep>::max(); } // TODO gated by gcc-9 (fixed in gcc-10)
{
return quantity_cast<quantity<U, ToRep>>(q);
return quantity(quantity_values<Rep>::max());
}
// quantity_values
[[nodiscard]] constexpr quantity operator+() const { return *this; }
template<Scalar Rep>
struct quantity_values {
static constexpr Rep zero() noexcept { return Rep(0); }
static constexpr Rep one() noexcept { return Rep(1); }
static constexpr Rep max() noexcept { return std::numeric_limits<Rep>::max(); }
static constexpr Rep min() noexcept { return std::numeric_limits<Rep>::lowest(); }
};
// quantity
template<Unit U, Scalar Rep = double>
class quantity {
Rep value_;
public:
using unit = U;
using rep = Rep;
using dimension = U::dimension;
quantity() = default;
quantity(const quantity&) = default;
quantity(quantity&&) = default;
template<Scalar Value>
requires detail::safe_convertible<Value, rep>
constexpr explicit quantity(const Value& v): value_{static_cast<rep>(v)}
{
}
template<Quantity Q2>
requires same_dim<dimension, typename Q2::dimension> &&
detail::safe_convertible<typename Q2::rep, rep> &&
detail::safe_divisible<rep, typename Q2::unit, unit>
constexpr quantity(const Q2& q): value_{quantity_cast<quantity>(q).count()}
{
}
quantity& operator=(const quantity&) = default;
quantity& operator=(quantity&&) = default;
[[nodiscard]] constexpr rep count() const noexcept { return value_; }
template<typename T = Rep>
[[nodiscard]] static constexpr quantity zero() noexcept
requires requires { quantity_values<T>::zero(); }
// requires requires { quantity_values<Rep>::zero(); } // TODO gated by gcc-9 (fixed in gcc-10)
{
return quantity(quantity_values<Rep>::zero());
}
template<typename T = Rep>
[[nodiscard]] static constexpr quantity one() noexcept
requires requires { quantity_values<T>::one(); }
// requires requires { quantity_values<Rep>::one(); } // TODO gated by gcc-9 (fixed in gcc-10)
{
return quantity(quantity_values<Rep>::one());
}
template<typename T = Rep>
[[nodiscard]] static constexpr quantity min() noexcept
requires requires { quantity_values<T>::min(); }
// requires requires { quantity_values<Rep>::min(); } // TODO gated by gcc-9 (fixed in gcc-10)
{
return quantity(quantity_values<Rep>::min());
}
template<typename T = Rep>
[[nodiscard]] static constexpr quantity max() noexcept
requires requires { quantity_values<T>::max(); }
// requires requires { quantity_values<Rep>::max(); } // TODO gated by gcc-9 (fixed in gcc-10)
{
return quantity(quantity_values<Rep>::max());
}
[[nodiscard]] constexpr quantity operator+() const { return *this; }
template<typename T = Rep>
[[nodiscard]] constexpr quantity operator-() const
requires std::regular_invocable<std::ranges::negate, T>
// requires std::regular_invocable<std::ranges::negate, rep> // TODO gated by gcc-9 (fixed in gcc-10)
{
return quantity(-count());
}
template<typename T = Rep>
constexpr quantity& operator++()
requires requires(T v) { { ++v } -> SAME_AS(T&); }
// requires requires(rep v) { { ++v } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
++value_;
return *this;
}
template<typename T = Rep>
requires requires(T v) { { v++ } -> SAME_AS(T); }
constexpr quantity operator++(int)
// requires requires(rep v) { { v++ } -> std::same_as<rep>; } // TODO gated by gcc-9 (fixed in gcc-10)
{ return quantity(value_++); }
template<typename T = Rep>
requires requires(T v) { { --v } -> SAME_AS(T&); }
constexpr quantity& operator--()
// requires requires(rep v) { { --v } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
--value_;
return *this;
}
template<typename T = Rep>
requires requires(T v) { { v-- } -> SAME_AS(T); }
constexpr quantity operator--(int)
// requires requires(rep v) { { v-- } -> std::same_as<rep>; } // TODO gated by gcc-9 (fixed in gcc-10)
{ return quantity(value_--); }
template<typename T = Rep>
requires requires(T v1, T v2) { { v1 += v2 } -> SAME_AS(T&); }
constexpr quantity& operator+=(const quantity& q)
// requires requires(rep v1, rep v2) { { v1 += v2 } -> std::same_as<T&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
value_ += q.count();
return *this;
}
template<typename T = Rep>
requires requires(T v1, T v2) { { v1 -= v2 } -> SAME_AS(T&); }
constexpr quantity& operator-=(const quantity& q)
// requires requires(rep v1, rep v2) { { v1 -= v2 } -> std::same_as<T&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
value_ -= q.count();
return *this;
}
template<typename T = Rep>
requires requires(T v1, T v2) { { v1 *= v2 } -> SAME_AS(T&); }
constexpr quantity& operator*=(const rep& rhs)
// requires requires(rep v1, rep v2) { { v1 *= v2 } -> std::same_as<T&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
value_ *= rhs;
return *this;
}
template<typename T = Rep>
requires requires(T v1, T v2) { { v1 /= v2 } -> SAME_AS(T&); }
constexpr quantity& operator/=(const rep& rhs)
// requires requires(rep v1, rep v2) { { v1 /= v2 } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
value_ /= rhs;
return *this;
}
template<Scalar Value, typename T = Rep>
constexpr quantity& operator%=(const Value& rhs)
requires (!treat_as_floating_point<rep>) &&
(!treat_as_floating_point<Value>) &&
requires(T v1, Value v2) { { v1 %= v2 } -> SAME_AS(T&); }
// requires(rep v1, Value v2) { { v1 %= v2 } -> SAME_AS(rep&); } // TODO gated by gcc-9 (fixed in gcc-10)
{
value_ %= rhs;
return *this;
}
template<typename T = Rep>
constexpr quantity& operator%=(const quantity& q)
requires (!treat_as_floating_point<rep>) &&
requires(T v1, T v2) { { v1 %= v2 } -> SAME_AS(T&); }
// requires(rep v1, rep v2) { { v1 %= v2 } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
value_ %= q.count();
return *this;
}
template<class CharT, class Traits>
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const quantity& q)
{
return os << q.count() << " " << detail::unit_text<quantity::unit>();
}
};
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator+(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> && detail::basic_arithmetic<Rep1, Rep2>
template<typename T = Rep>
[[nodiscard]] constexpr quantity operator-() const
requires std::regular_invocable<std::ranges::negate, T>
// requires std::regular_invocable<std::ranges::negate, rep> // TODO gated by gcc-9 (fixed in gcc-10)
{
using common_rep = decltype(lhs.count() + rhs.count());
using ret = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
return ret(ret(lhs).count() + ret(rhs).count());
return quantity(-count());
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator-(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2>
template<typename T = Rep>
constexpr quantity& operator++()
requires requires(T v) { { ++v } -> SAME_AS(T&); }
// requires requires(rep v) { { ++v } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
using common_rep = decltype(lhs.count() - rhs.count());
using ret = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
return ret(ret(lhs).count() - ret(rhs).count());
++value_;
return *this;
}
template<typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator*(const quantity<U, Rep>& q, const Value& v)
requires std::magma<std::ranges::times, Rep, Value>
template<typename T = Rep>
requires requires(T v) { { v++ } -> SAME_AS(T); }
constexpr quantity operator++(int)
// requires requires(rep v) { { v++ } -> std::same_as<rep>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
using common_rep = decltype(q.count() * v);
using ret = quantity<U, common_rep>;
return ret(q.count() * v);
return quantity(value_++);
}
template<Scalar Value, typename U, typename Rep>
[[nodiscard]] constexpr Quantity AUTO operator*(const Value& v, const quantity<U, Rep>& q)
requires std::magma<std::ranges::times, Value, Rep>
template<typename T = Rep>
requires requires(T v) { { --v } -> SAME_AS(T&); }
constexpr quantity& operator--()
// requires requires(rep v) { { --v } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
return q * v;
--value_;
return *this;
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator*(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, dim_invert<typename U2::dimension>> &&
detail::basic_arithmetic<Rep1, Rep2>
template<typename T = Rep>
requires requires(T v) { { v-- } -> SAME_AS(T); }
constexpr quantity operator--(int)
// requires requires(rep v) { { v-- } -> std::same_as<rep>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
using common_rep = decltype(lhs.count() * rhs.count());
using ratio = ratio_multiply<typename U1::ratio, typename U2::ratio>;
return common_rep(lhs.count()) * common_rep(rhs.count()) * common_rep(ratio::num) / common_rep(ratio::den);
return quantity(value_--);
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator*(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires (!same_dim<typename U1::dimension, dim_invert<typename U2::dimension>>) &&
(treat_as_floating_point<decltype(lhs.count() * rhs.count())> ||
(std::ratio_multiply<typename U1::ratio, typename U2::ratio>::den == 1)) &&
detail::basic_arithmetic<Rep1, Rep2>
template<typename T = Rep>
requires requires(T v1, T v2) { { v1 += v2 } -> SAME_AS(T&); }
constexpr quantity& operator+=(const quantity& q)
// requires requires(rep v1, rep v2) { { v1 += v2 } -> std::same_as<T&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
using dim = dimension_multiply<typename U1::dimension, typename U2::dimension>;
using common_rep = decltype(lhs.count() * rhs.count());
using ret = quantity<downcast<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, common_rep>;
return ret(lhs.count() * rhs.count());
value_ += q.count();
return *this;
}
template<Scalar Value, typename U, typename Rep>
[[nodiscard]] constexpr Quantity AUTO operator/(const Value& v, const quantity<U, Rep>& q)
requires std::magma<std::ranges::divided_by, Value, Rep>
template<typename T = Rep>
requires requires(T v1, T v2) { { v1 -= v2 } -> SAME_AS(T&); }
constexpr quantity& operator-=(const quantity& q)
// requires requires(rep v1, rep v2) { { v1 -= v2 } -> std::same_as<T&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
Expects(q != std::remove_cvref_t<decltype(q)>(0));
using dim = dim_invert<typename U::dimension>;
using common_rep = decltype(v / q.count());
using ret = quantity<downcast<unit<dim, ratio<U::ratio::den, U::ratio::num>>>, common_rep>;
return ret(v / q.count());
value_ -= q.count();
return *this;
}
template<typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<U, Rep>& q, const Value& v)
requires std::magma<std::ranges::divided_by, Rep, Value>
template<typename T = Rep>
requires requires(T v1, T v2) { { v1 *= v2 } -> SAME_AS(T&); }
constexpr quantity& operator*=(const rep& rhs)
// requires requires(rep v1, rep v2) { { v1 *= v2 } -> std::same_as<T&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
Expects(v != Value{0});
using common_rep = decltype(q.count() / v);
using ret = quantity<U, common_rep>;
return ret(q.count() / v);
value_ *= rhs;
return *this;
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator/(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2>
template<typename T = Rep>
requires requires(T v1, T v2) { { v1 /= v2 } -> SAME_AS(T&); }
constexpr quantity& operator/=(const rep& rhs)
// requires requires(rep v1, rep v2) { { v1 /= v2 } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
using common_rep = decltype(lhs.count() / rhs.count());
using cq = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
return cq(lhs).count() / cq(rhs).count();
value_ /= rhs;
return *this;
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires (!same_dim<typename U1::dimension, typename U2::dimension>) &&
(treat_as_floating_point<decltype(lhs.count() / rhs.count())> ||
(ratio_divide<typename U1::ratio, typename U2::ratio>::den == 1)) &&
detail::basic_arithmetic<Rep1, Rep2>
template<Scalar Value, typename T = Rep>
constexpr quantity& operator%=(const Value& rhs)
requires (!treat_as_floating_point<rep>) &&
(!treat_as_floating_point<Value>) &&
requires(T v1, Value v2) { { v1 %= v2 } -> SAME_AS(T&); }
// requires(rep v1, Value v2) { { v1 %= v2 } -> SAME_AS(rep&); } // TODO gated by gcc-9 (fixed in gcc-10)
{
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
using common_rep = decltype(lhs.count() / rhs.count());
using dim = dimension_divide<typename U1::dimension, typename U2::dimension>;
using ret = quantity<downcast<unit<dim, ratio_divide<typename U1::ratio, typename U2::ratio>>>, common_rep>;
return ret(lhs.count() / rhs.count());
value_ %= rhs;
return *this;
}
template<typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator%(const quantity<U, Rep>& q, const Value& v)
requires (!treat_as_floating_point<Rep>) && (!treat_as_floating_point<Value>) &&
std::magma<std::ranges::modulus, Rep, Value>
template<typename T = Rep>
constexpr quantity& operator%=(const quantity& q)
requires (!treat_as_floating_point<rep>) &&
requires(T v1, T v2) { { v1 %= v2 } -> SAME_AS(T&); }
// requires(rep v1, rep v2) { { v1 %= v2 } -> std::same_as<rep&>; } // TODO gated by gcc-9 (fixed in gcc-10)
{
using common_rep = decltype(q.count() % v);
using ret = quantity<U, common_rep>;
return ret(q.count() % v);
value_ %= q.count();
return *this;
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator%(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires (!treat_as_floating_point<Rep1>) && (!treat_as_floating_point<Rep2>) &&
std::magma<std::ranges::modulus, Rep1, Rep2>
#if __GNUC__ >= 10
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
detail::basic_arithmetic<Rep, Rep2> &&
std::totally_ordered_with<Rep, Rep2>
{
using common_rep = decltype(lhs.count() % rhs.count());
using ret = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
return ret(ret(lhs).count() % ret(rhs).count());
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
return cq(lhs).count() <=> cq(rhs).count();
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator==(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::equality_comparable_with<Rep1, Rep2>
// TODO op== not needed (gcc bug)
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr auto operator==(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
detail::basic_arithmetic<Rep, Rep2> &&
std::equality_comparable_with<Rep, Rep2>
{
using cq = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>>;
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
return cq(lhs).count() == cq(rhs).count();
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator!=(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::equality_comparable_with<Rep1, Rep2>
#else
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
detail::basic_arithmetic<Rep, Rep2> &&
std::equality_comparable_with<Rep, Rep2>
{
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
return cq(lhs).count() == cq(rhs).count();
}
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator!=(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
detail::basic_arithmetic<Rep, Rep2> &&
std::equality_comparable_with<Rep, Rep2>
{
return !(lhs == rhs);
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator<(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::totally_ordered_with<Rep1, Rep2>
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator<(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
detail::basic_arithmetic<Rep, Rep2> &&
std::totally_ordered_with<Rep, Rep2>
{
using cq = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>>;
using cq = common_quantity<quantity, quantity<D2, U2, Rep2>>;
return cq(lhs).count() < cq(rhs).count();
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator<=(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::totally_ordered_with<Rep1, Rep2>
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator<=(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
detail::basic_arithmetic<Rep, Rep2> &&
std::totally_ordered_with<Rep, Rep2>
{
return !(rhs < lhs);
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator>(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::totally_ordered_with<Rep1, Rep2>
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator>(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
detail::basic_arithmetic<Rep, Rep2> &&
std::totally_ordered_with<Rep, Rep2>
{
return rhs < lhs;
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator>=(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::totally_ordered_with<Rep1, Rep2>
template<typename D2, typename U2, typename Rep2>
[[nodiscard]] friend constexpr bool operator>=(const quantity& lhs, const quantity<D2, U2, Rep2>& rhs)
requires equivalent_dim<D, D2> &&
detail::basic_arithmetic<Rep, Rep2> &&
std::totally_ordered_with<Rep, Rep2>
{
return !(lhs < rhs);
}
#endif
template<class CharT, class Traits>
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const quantity& q)
{
return os << q.count() << " " << detail::unit_text<quantity::dimension, quantity::unit>();
}
};
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator+(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2>
{
using common_rep = decltype(lhs.count() + rhs.count());
using ret = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() + ret(rhs).count());
}
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator-(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2>
{
using common_rep = decltype(lhs.count() - rhs.count());
using ret = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() - ret(rhs).count());
}
template<typename D, typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator*(const quantity<D, U, Rep>& q, const Value& v)
requires std::magma<std::ranges::times, Rep, Value>
{
using common_rep = decltype(q.count() * v);
using ret = quantity<D, U, common_rep>;
return ret(q.count() * v);
}
template<Scalar Value, typename D, typename U, typename Rep>
[[nodiscard]] constexpr Quantity AUTO operator*(const Value& v, const quantity<D, U, Rep>& q)
requires std::magma<std::ranges::times, Value, Rep>
{
return q * v;
}
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator*(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2> && equivalent_dim<D1, dim_invert<D2>>
{
using common_rep = decltype(lhs.count() * rhs.count());
using ratio = ratio_multiply<typename U1::ratio, typename U2::ratio>;
return common_rep(lhs.count()) * common_rep(rhs.count()) * common_rep(ratio::num) / common_rep(ratio::den);
}
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator*(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent_dim<D1, dim_invert<D2>>) // TODO equivalent_derived_dim?
{
using dim = dimension_multiply<D1, D2>;
using ratio1 = ratio_divide<typename U1::ratio, typename dimension_unit<D1>::ratio>;
using ratio2 = ratio_divide<typename U2::ratio, typename dimension_unit<D2>::ratio>;
using ratio = ratio_multiply<ratio_multiply<ratio1, ratio2>, typename dimension_unit<dim>::ratio>;
using unit = downcast_unit<dim, ratio>;
using common_rep = decltype(lhs.count() * rhs.count());
using ret = quantity<dim, unit, common_rep>;
return ret(lhs.count() * rhs.count());
}
template<Scalar Value, typename D, typename U, typename Rep>
[[nodiscard]] constexpr Quantity AUTO operator/(const Value& v, const quantity<D, U, Rep>& q)
requires std::magma<std::ranges::divided_by, Value, Rep>
{
Expects(q.count() != 0);
using dim = dim_invert<D>;
using ratio = ratio<U::ratio::den, U::ratio::num>;
using unit = downcast_unit<dim, ratio>;
using common_rep = decltype(v / q.count());
using ret = quantity<dim, unit, common_rep>;
return ret(v / q.count());
}
template<typename D, typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<D, U, Rep>& q, const Value& v)
requires std::magma<std::ranges::divided_by, Rep, Value>
{
Expects(v != Value{0});
using common_rep = decltype(q.count() / v);
using ret = quantity<D, U, common_rep>;
return ret(q.count() / v);
}
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator/(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2> && equivalent_dim<D1, D2>
{
Expects(rhs.count() != 0);
using common_rep = decltype(lhs.count() / rhs.count());
using cq = common_quantity<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, common_rep>;
return cq(lhs).count() / cq(rhs).count();
}
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent_dim<D1, D2>) // TODO equivalent_derived_dim?
{
Expects(rhs.count() != 0);
using common_rep = decltype(lhs.count() / rhs.count());
using dim = dimension_divide<D1, D2>;
using ratio1 = ratio_divide<typename U1::ratio, typename dimension_unit<D1>::ratio>;
using ratio2 = ratio_divide<typename U2::ratio, typename dimension_unit<D2>::ratio>;
using ratio = ratio_multiply<ratio_divide<ratio1, ratio2>, typename dimension_unit<dim>::ratio>;
using unit = downcast_unit<dim, ratio>;
using ret = quantity<dim, unit, common_rep>;
return ret(lhs.count() / rhs.count());
}
template<typename D, typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator%(const quantity<D, U, Rep>& q, const Value& v)
requires (!treat_as_floating_point<Rep>) &&
(!treat_as_floating_point<Value>) &&
std::magma<std::ranges::modulus, Rep, Value>
{
using common_rep = decltype(q.count() % v);
using ret = quantity<D, U, common_rep>;
return ret(q.count() % v);
}
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator%(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires (!treat_as_floating_point<Rep1>) &&
(!treat_as_floating_point<Rep2>) &&
std::magma<std::ranges::modulus, Rep1, Rep2>
{
using common_rep = decltype(lhs.count() % rhs.count());
using ret = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() % ret(rhs).count());
}
namespace detail {
template<typename D, typename U, typename Rep>
inline constexpr bool is_quantity<quantity<D, U, Rep>> = true;
} // namespace detail
} // namespace units

View File

@@ -0,0 +1,188 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/concepts.h>
#include <units/bits/dimension_op.h>
namespace units {
// QuantityOf
template<typename T, typename Dim>
concept QuantityOf = Quantity<T> && Dimension<Dim> && equivalent_dim<typename T::dimension, Dim>;
// quantity_cast
namespace detail {
template<typename To, typename CRatio, typename CRep, bool NumIsOne = false, bool DenIsOne = false>
struct quantity_cast_impl {
template<typename Q>
static constexpr To cast(const Q& q)
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) *
(static_cast<CRep>(CRatio::num) / static_cast<CRep>(CRatio::den))));
} else {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num) /
static_cast<CRep>(CRatio::den)));
}
}
};
template<typename To, typename CRatio, typename CRep>
struct quantity_cast_impl<To, CRatio, CRep, true, true> {
template<Quantity Q>
static constexpr To cast(const Q& q)
{
return To(static_cast<To::rep>(q.count()));
}
};
template<typename To, typename CRatio, typename CRep>
struct quantity_cast_impl<To, CRatio, CRep, true, false> {
template<Quantity Q>
static constexpr To cast(const Q& q)
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * (CRep{1} / static_cast<CRep>(CRatio::den))));
} else {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(CRatio::den)));
}
}
};
template<typename To, typename CRatio, typename CRep>
struct quantity_cast_impl<To, CRatio, CRep, false, true> {
template<Quantity Q>
static constexpr To cast(const Q& q)
{
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num)));
}
};
template<Dimension FromD, Unit FromU, Dimension ToD, Unit ToU>
struct cast_ratio;
template<BaseDimension FromD, Unit FromU, BaseDimension ToD, Unit ToU>
struct cast_ratio<FromD, FromU, ToD, ToU> {
using type = ratio_divide<typename FromU::ratio, typename ToU::ratio>;
};
template<DerivedDimension FromD, Unit FromU, DerivedDimension ToD, Unit ToU>
requires same_unit_reference<FromU, ToU>::value
struct cast_ratio<FromD, FromU, ToD, ToU> {
using type = ratio_divide<typename FromU::ratio, typename ToU::ratio>;
};
template<DerivedDimension FromD, Unit FromU, DerivedDimension ToD, Unit ToU>
struct cast_ratio<FromD, FromU, ToD, ToU> {
using from_ratio = ratio_multiply<typename FromD::base_units_ratio, typename FromU::ratio>;
using to_ratio = ratio_multiply<typename ToD::base_units_ratio, typename ToU::ratio>;
using type = ratio_divide<from_ratio, to_ratio>;
};
} // namespace detail
/**
* @brief Explcit cast of a quantity
*
* Implicit conversions between quantities of different types are allowed only for "safe"
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
*
* This cast gets the target quantity type to cast to. For example:
*
* auto q1 = units::quantity_cast<units::si::time<units::si::second>>(1ms);
*
* @tparam To a target quantity type to cast to
*/
template<Quantity To, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires QuantityOf<To, D> &&
detail::basic_arithmetic<std::common_type_t<typename To::rep, Rep, intmax_t>>
{
using c_ratio = detail::cast_ratio<D, U, typename To::dimension, typename To::unit>::type;
using c_rep = std::common_type_t<typename To::rep, Rep, intmax_t>;
using ret_unit = downcast_unit<typename To::dimension, typename To::unit::ratio>;
using ret = quantity<typename To::dimension, ret_unit, typename To::rep>;
using cast = detail::quantity_cast_impl<ret, c_ratio, c_rep, c_ratio::num == 1, c_ratio::den == 1>;
return cast::cast(q);
}
/**
* @brief Explcit cast of a quantity
*
* Implicit conversions between quantities of different types are allowed only for "safe"
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
*
* This cast gets only the target dimension to cast to. For example:
*
* auto q1 = units::quantity_cast<units::si::acceleration>(200Gal);
*
* @tparam ToD a dimension type to use for a target quantity
*/
template<Dimension ToD, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires equivalent_dim<ToD, D>
{
return quantity_cast<quantity<ToD, dimension_unit<ToD>, Rep>>(q);
}
/**
* @brief Explcit cast of a quantity
*
* Implicit conversions between quantities of different types are allowed only for "safe"
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
*
* This cast gets only the target unit to cast to. For example:
*
* auto q1 = units::quantity_cast<units::si::second>(1ms);
*
* @tparam ToU a unit type to use for a target quantity
*/
template<Unit ToU, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires UnitOf<ToU, D>
{
return quantity_cast<quantity<D, ToU, Rep>>(q);
}
/**
* @brief Explcit cast of a quantity
*
* Implicit conversions between quantities of different types are allowed only for "safe"
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
*
* This cast gets only representation to cast to. For example:
*
* auto q1 = units::quantity_cast<int>(1ms);
*
* @tparam ToRep a representation type to use for a target quantity
*/
template<Scalar ToRep, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires detail::basic_arithmetic<std::common_type_t<ToRep, Rep, intmax_t>>
{
return quantity_cast<quantity<D, U, ToRep>>(q);
}
} // namespace units

View File

@@ -22,178 +22,180 @@
#pragma once
#include <units/bits/hacks.h>
#include <type_traits>
#include <numeric>
#include <units/bits/external/hacks.h>
#include <units/concepts.h>
#include <cstdint>
#include <numeric>
#include <type_traits>
namespace units {
namespace detail {
namespace detail {
template<typename T>
[[nodiscard]] constexpr T abs(T v) noexcept { return v < 0 ? -v : v; }
template<typename T>
[[nodiscard]] constexpr T abs(T v) noexcept
{
return v < 0 ? -v : v;
}
}
} // namespace detail
template<std::intmax_t Num, std::intmax_t Den = 1>
requires (Den != 0)
struct ratio {
static_assert(-INTMAX_MAX <= Num, "numerator too negative");
static_assert(-INTMAX_MAX <= Den, "denominator too negative");
template<std::intmax_t Num, std::intmax_t Den = 1>
requires(Den != 0)
struct ratio {
static_assert(-INTMAX_MAX <= Num, "numerator too negative");
static_assert(-INTMAX_MAX <= Den, "denominator too negative");
static constexpr std::intmax_t num = Num * (Den < 0 ? -1 : 1) / std::gcd(Num, Den);
static constexpr std::intmax_t den = detail::abs(Den) / std::gcd(Num, Den);
static constexpr std::intmax_t num = Num * (Den < 0 ? -1 : 1) / std::gcd(Num, Den);
static constexpr std::intmax_t den = detail::abs(Den) / std::gcd(Num, Den);
using type = ratio<num, den>;
};
using type = ratio<num, den>;
};
// is_ratio
namespace detail {
namespace detail {
template<intmax_t Num, intmax_t Den>
inline constexpr bool is_ratio<ratio<Num, Den>> = true;
template<typename T>
inline constexpr bool is_ratio = false;
template<intmax_t Num, intmax_t Den>
inline constexpr bool is_ratio<ratio<Num, Den>> = true;
} // namespace detail
template<typename T>
concept Ratio = detail::is_ratio<T>;
// ratio_multiply
namespace detail {
static constexpr std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs)
{
constexpr std::uintmax_t c = std::uintmax_t(1) << (sizeof(std::intmax_t) * 4);
const std::uintmax_t a0 = detail::abs(lhs) % c;
const std::uintmax_t a1 = detail::abs(lhs) / c;
const std::uintmax_t b0 = detail::abs(rhs) % c;
const std::uintmax_t b1 = detail::abs(rhs) / c;
Expects(a1 == 0 || b1 == 0); // overflow in multiplication
Expects(a0 * b1 + b0 * a1 < (c >> 1)); // overflow in multiplication
Expects(b0 * a0 <= INTMAX_MAX); // overflow in multiplication
Expects((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0); // overflow in multiplication
return lhs * rhs;
}
template<typename R1, typename R2>
struct ratio_multiply_impl {
private:
static constexpr std::intmax_t gcd1 = std::gcd(R1::num, R2::den);
static constexpr std::intmax_t gcd2 = std::gcd(R2::num, R1::den);
public:
using type = ratio<safe_multiply(R1::num / gcd1, R2::num / gcd2), safe_multiply(R1::den / gcd2, R2::den / gcd1)>;
static constexpr std::intmax_t num = type::num;
static constexpr std::intmax_t den = type::den;
};
}
template<Ratio R1, Ratio R2>
using ratio_multiply = detail::ratio_multiply_impl<R1, R2>::type;
// ratio_divide
namespace detail {
template<typename R1, typename R2>
struct ratio_divide_impl {
static_assert(R2::num != 0, "division by 0");
using type = ratio_multiply<R1, ratio<R2::den, R2::num>>;
static constexpr std::intmax_t num = type::num;
static constexpr std::intmax_t den = type::den;
};
}
template<Ratio R1, Ratio R2>
using ratio_divide = detail::ratio_divide_impl<R1, R2>::type;
// ratio_pow
namespace detail {
template<typename R, std::size_t N>
struct ratio_pow_impl {
using type = ratio_multiply<typename ratio_pow_impl<R, N - 1>::type, R>;
};
template<typename R>
struct ratio_pow_impl<R, 1> {
using type = R;
};
template<typename R>
struct ratio_pow_impl<R, 0> {
using type = ratio<1>;
};
}
template<Ratio R, std::size_t N>
using ratio_pow = detail::ratio_pow_impl<R, N>::type;
// ratio_sqrt
namespace detail {
constexpr std::intmax_t sqrt_impl(std::intmax_t v, std::intmax_t l, std::intmax_t r)
{
if(l == r)
return r;
const auto mid = (r + l) / 2;
if(mid * mid >= v)
return sqrt_impl(v, l, mid);
else
return sqrt_impl(v, mid + 1, r);
}
static constexpr std::intmax_t sqrt_impl(std::intmax_t v)
{
return sqrt_impl(v, 1, v);
}
template<typename R>
struct ratio_sqrt_impl {
using type = ratio<detail::sqrt_impl(R::num), detail::sqrt_impl(R::den)>;
};
template<std::intmax_t Den>
struct ratio_sqrt_impl<ratio<0, Den>> {
using type = ratio<0>;
};
}
template<Ratio R>
using ratio_sqrt = detail::ratio_sqrt_impl<R>::type;
} // namespace detail
// common_ratio
// ratio_add
// TODO implement ratio_add
// template<Ratio R1, Ratio R2>
// using ratio_add = detail::ratio_add_impl<R1, R2>::type;
namespace detail {
// ratio_subtract
// TODO implement ratio_subtract
// template<Ratio R1, Ratio R2>
// using ratio_subtract = detail::ratio_subtract_impl<R1, R2>::type;
// TODO: simplified
template<typename R1, typename R2>
struct common_ratio_impl {
static constexpr std::intmax_t gcd_num = std::gcd(R1::num, R2::num);
static constexpr std::intmax_t gcd_den = std::gcd(R1::den, R2::den);
using type = ratio<gcd_num, (R1::den / gcd_den) * R2::den>;
};
// ratio_multiply
}
namespace detail {
template<Ratio R1, Ratio R2>
using common_ratio = detail::common_ratio_impl<R1, R2>::type;
static constexpr std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs)
{
constexpr std::uintmax_t c = std::uintmax_t(1) << (sizeof(std::intmax_t) * 4);
const std::uintmax_t a0 = detail::abs(lhs) % c;
const std::uintmax_t a1 = detail::abs(lhs) / c;
const std::uintmax_t b0 = detail::abs(rhs) % c;
const std::uintmax_t b1 = detail::abs(rhs) / c;
Expects(a1 == 0 || b1 == 0); // overflow in multiplication
Expects(a0 * b1 + b0 * a1 < (c >> 1)); // overflow in multiplication
Expects(b0 * a0 <= INTMAX_MAX); // overflow in multiplication
Expects((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0); // overflow in multiplication
return lhs * rhs;
}
template<typename R1, typename R2>
struct ratio_multiply_impl {
private:
static constexpr std::intmax_t gcd1 = std::gcd(R1::num, R2::den);
static constexpr std::intmax_t gcd2 = std::gcd(R2::num, R1::den);
public:
using type = ratio<safe_multiply(R1::num / gcd1, R2::num / gcd2), safe_multiply(R1::den / gcd2, R2::den / gcd1)>;
static constexpr std::intmax_t num = type::num;
static constexpr std::intmax_t den = type::den;
};
} // namespace detail
template<Ratio R1, Ratio R2>
using ratio_multiply = detail::ratio_multiply_impl<R1, R2>::type;
// ratio_divide
namespace detail {
template<typename R1, typename R2>
struct ratio_divide_impl {
static_assert(R2::num != 0, "division by 0");
using type = ratio_multiply<R1, ratio<R2::den, R2::num>>;
static constexpr std::intmax_t num = type::num;
static constexpr std::intmax_t den = type::den;
};
} // namespace detail
template<Ratio R1, Ratio R2>
using ratio_divide = detail::ratio_divide_impl<R1, R2>::type;
// ratio_pow
namespace detail {
template<typename R, std::size_t N>
struct ratio_pow_impl {
using type = ratio_multiply<typename ratio_pow_impl<R, N - 1>::type, R>;
};
template<typename R>
struct ratio_pow_impl<R, 1> {
using type = R;
};
template<typename R>
struct ratio_pow_impl<R, 0> {
using type = ratio<1>;
};
} // namespace detail
template<Ratio R, std::size_t N>
using ratio_pow = detail::ratio_pow_impl<R, N>::type;
// ratio_sqrt
namespace detail {
constexpr std::intmax_t sqrt_impl(std::intmax_t v, std::intmax_t l, std::intmax_t r)
{
if (l == r) return r;
const auto mid = (r + l) / 2;
if (mid * mid >= v)
return sqrt_impl(v, l, mid);
else
return sqrt_impl(v, mid + 1, r);
}
static constexpr std::intmax_t sqrt_impl(std::intmax_t v) { return sqrt_impl(v, 1, v); }
template<typename R>
struct ratio_sqrt_impl {
using type = ratio<detail::sqrt_impl(R::num), detail::sqrt_impl(R::den)>;
};
template<std::intmax_t Den>
struct ratio_sqrt_impl<ratio<0, Den>> {
using type = ratio<0>;
};
} // namespace detail
template<Ratio R>
using ratio_sqrt = detail::ratio_sqrt_impl<R>::type;
// common_ratio
namespace detail {
// TODO: simplified
template<typename R1, typename R2>
struct common_ratio_impl {
static constexpr std::intmax_t gcd_num = std::gcd(R1::num, R2::num);
static constexpr std::intmax_t gcd_den = std::gcd(R1::den, R2::den);
using type = ratio<gcd_num, (R1::den / gcd_den) * R2::den>;
};
} // namespace detail
template<Ratio R1, Ratio R2>
using common_ratio = detail::common_ratio_impl<R1, R2>::type;
} // namespace units

View File

@@ -22,353 +22,157 @@
#pragma once
#include <units/dimension.h>
#include <units/bits/deduced_symbol_text.h>
#include <units/bits/deduced_unit.h>
#include <units/bits/external/downcasting.h>
#include <units/bits/external/fixed_string.h>
#include <units/bits/external/text_tools.h>
#include <units/bits/external/type_traits.h>
#include <units/derived_dimension.h>
#include <units/prefix.h>
#include <units/ratio.h>
#include <ratio>
namespace units {
template<Dimension D, Ratio R>
requires (R::num * R::den > 0)
struct unit : downcast_base<unit<D, R>> {
using dimension = D;
using ratio = R;
};
/**
* @brief A common point for a hierarchy of units
*
* A unit is an entity defined and adopted by convention, with which any other quantity of
* the same kind can be compared to express the ratio of the second quantity to the first
* one as a number.
*
* All units of the same dimension can be convereted between each other. To allow this all of
* them are expressed as different ratios of the same one proprietary chosen reference unit
* (i.e. all length units are expressed in terms of meter, all mass units are expressed in
* terms of gram, ...)
*
* @tparam U a unit to use as a reference for this dimension
* @tparam R a ratio of a reference unit
*/
template<UnitRatio R, typename U>
struct scaled_unit : downcast_base<scaled_unit<R, U>> {
using ratio = R;
using reference = U;
};
// is_unit
template<Dimension D, UnitRatio R>
using downcast_unit = downcast<scaled_unit<R, typename dimension_unit<D>::reference>>;
namespace detail {
template<Unit U1, Unit U2>
struct same_unit_reference : std::is_same<typename U1::reference, typename U2::reference> {};
template<typename T>
inline constexpr bool is_unit = false;
/**
* @brief An unnamed unit
*
* Defines a new unnamed (in most cases coherent) derived unit of a specific derived dimension
* and it should be passed in this dimension's definition.
*
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
*/
template<typename Child>
struct unit : downcast_child<Child, scaled_unit<ratio<1>, Child>> {
static constexpr bool is_named = false;
using prefix_type = no_prefix;
};
template<typename D, typename R>
inline constexpr bool is_unit<unit<D, R>> = true;
/**
* @brief Unknown unit
*
* Used as a coherent unit of an unknown dimension.
*/
struct unknown_unit : unit<unknown_unit> {};
}
/**
* @brief A named unit
*
* Defines a named (in most cases coherent) unit that is then passed to a dimension definition.
* A named unit may be used by other units defined with the prefix of the same type, unless
* no_prefix is provided for PT template parameter (in such a case it is impossible to define
* a prefix unit based on this one).
*
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
* @tparam Symbol a short text representation of the unit
* @tparam PT no_prefix or a type of prefix family
*/
template<typename Child, basic_fixed_string Symbol, PrefixType PT>
struct named_unit : downcast_child<Child, scaled_unit<ratio<1>, Child>> {
static constexpr bool is_named = true;
static constexpr auto symbol = Symbol;
using prefix_type = PT;
};
template<typename T>
concept Unit =
std::is_empty_v<T> &&
detail::is_unit<downcast_base_t<T>>;
/**
* @brief A scaled unit
*
* Defines a new named unit that is a scaled version of another unit. Such unit can be used by
* other units defined with the prefix of the same type, unless no_prefix is provided for PT
* template parameter (in such a case it is impossible to define a prefix unit based on this
* one).
*
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
* @tparam Symbol a short text representation of the unit
* @tparam PT no_prefix or a type of prefix family
* @tparam R a scale to apply to U
* @tparam U a reference unit to scale
*/
template<typename Child, basic_fixed_string Symbol, PrefixType PT, UnitRatio R, Unit U>
struct named_scaled_unit : downcast_child<Child, scaled_unit<ratio_multiply<R, typename U::ratio>, typename U::reference>> {
static constexpr bool is_named = true;
static constexpr auto symbol = Symbol;
using prefix_type = PT;
};
// deduced_derived_unit
/**
* @brief A prefixed unit
*
* Defines a new unit that is a scaled version of another unit by the provided prefix. It is
* only possible to create such a unit if the given prefix type matches the one defined in a
* reference unit.
*
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
* @tparam P prefix to be appied to the reference unit
* @tparam U reference unit
*/
template<typename Child, Prefix P, Unit U>
requires std::same_as<typename P::prefix_type, typename U::prefix_type>
// TODO replace with the below code when gcc will stop to crash on it ;-)
// struct prefixed_unit : named_scaled_unit<Child, P::symbol + U::symbol, typename P::prefix_type,
// ratio_multiply<typename P::ratio, typename U::ratio>,
// typename U::reference> {};
struct prefixed_unit :
downcast_child<Child, scaled_unit<ratio_multiply<typename P::ratio, typename U::ratio>, typename U::reference>> {
static constexpr bool is_named = true;
static constexpr auto symbol = P::symbol + U::symbol;
using prefix_type = P::prefix_type;
};
namespace detail {
/**
* @brief A unit with a deduced ratio and symbol
*
* Defines a new unit with a deduced ratio and symbol based on the recipe from the provided
* derived dimension. The number and order of provided units should match the recipe of the
* derived dimension. All of the units provided should also be a named ones so it is possible
* to create a deduced symbol text.
*
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
* @tparam Dim a derived dimension recipe to use for deduction
* @tparam U the unit of the first composite dimension from provided derived dimension's recipe
* @tparam URest the units for the rest of dimensions from the recipe
*/
template<typename Child, DerivedDimension Dim, Unit U, Unit... URest>
requires detail::same_scaled_units<typename Dim::recipe, U, URest...> &&
(U::is_named && (URest::is_named && ... && true))
struct deduced_unit : downcast_child<Child, detail::deduced_unit<Dim, U, URest...>> {
static constexpr bool is_named = false;
static constexpr auto symbol = detail::deduced_symbol_text<Dim, U, URest...>();
using prefix_type = no_prefix;
};
template<typename D>
struct get_unit_base_dim;
template<typename E, typename... Rest>
struct get_unit_base_dim<dimension<E, Rest...>> {
static_assert(sizeof...(Rest) == 0, "Base unit expected");
using dimension = E::dimension;
};
template<typename Result, int UnitExpNum, int UnitExpDen, typename UnitRatio>
struct ratio_op;
template<typename Result, int UnitExpDen, typename UnitRatio>
struct ratio_op<Result, 0, UnitExpDen, UnitRatio> {
using ratio = Result;
};
template<typename Result, int UnitExpNum, int UnitExpDen, typename UnitRatio>
struct ratio_op {
using calc_ratio = conditional<(UnitExpNum * UnitExpDen > 0), ratio_multiply<Result, UnitRatio>,
ratio_divide<Result, UnitRatio>>;
static constexpr int value = (UnitExpNum * UnitExpDen > 0) ? (UnitExpNum - UnitExpDen) : (UnitExpNum + UnitExpDen);
using ratio = ratio_op<calc_ratio, value, UnitExpDen, UnitRatio>::ratio;
};
template<typename D, typename... Us>
struct derived_ratio;
template<typename... Us>
struct derived_ratio<dimension<>, Us...> {
using ratio = ::units::ratio<1>;
};
template<typename E, typename... ERest, typename U, typename... URest>
struct derived_ratio<dimension<E, ERest...>, U, URest...> {
static_assert(same_dim<typename E::dimension, typename U::dimension>, "The order and number of units in `deduced_derived_unit<Us...>` should match dimensions provided in a `derived_dimension<>`");
static_assert(sizeof...(ERest) == sizeof...(URest), "The number of `deduced_derived_unit<Us...>` units should match the number of exponents provided to `derived_dimension<>`");
using rest_ratio = derived_ratio<dimension<ERest...>, URest...>::ratio;
using ratio = ratio_op<rest_ratio, E::num, E::den, typename U::ratio>::ratio;
};
template<typename... Es>
constexpr auto exp_count(dimension<Es...>)
{
return sizeof...(Es);
}
template<typename U>
inline constexpr bool is_unit_of_base_dimension = (exp_count(typename U::dimension::base_type()) == 1);
template<Unit... Us>
inline constexpr bool are_units_of_base_dimension = (is_unit_of_base_dimension<Us> && ...);
template<Dimension D, Unit... Us>
using deduced_derived_unit =
unit<D, typename detail::derived_ratio<std::conditional_t<are_units_of_base_dimension<Us...>,
typename D::base_type, typename D::recipe>, Us...>::ratio>;
template<int Value>
requires (0 <= Value) && (Value < 10)
inline constexpr basic_fixed_string superscript_number = "\u2070";
// template<> inline constexpr basic_fixed_string superscript_number<0> = "\u2070";
template<> inline constexpr basic_fixed_string superscript_number<1> = "\u00b9";
template<> inline constexpr basic_fixed_string superscript_number<2> = "\u00b2";
template<> inline constexpr basic_fixed_string superscript_number<3> = "\u00b3";
template<> inline constexpr basic_fixed_string superscript_number<4> = "\u2074";
template<> inline constexpr basic_fixed_string superscript_number<5> = "\u2075";
template<> inline constexpr basic_fixed_string superscript_number<6> = "\u2076";
template<> inline constexpr basic_fixed_string superscript_number<7> = "\u2077";
template<> inline constexpr basic_fixed_string superscript_number<8> = "\u2078";
template<> inline constexpr basic_fixed_string superscript_number<9> = "\u2079";
template<int Value>
requires (Value >= 0)
constexpr auto superscript()
{
if constexpr(Value < 10)
return superscript_number<Value>;
else
return superscript<Value / 10>() + superscript<Value % 10>();
}
template<int Value>
requires (Value >= 0)
constexpr auto regular()
{
if constexpr(Value < 10)
return basic_fixed_string(static_cast<char>('0' + Value));
else
return regular<Value / 10>() + regular<Value % 10>();
}
template<typename Ratio>
constexpr auto ratio_text()
{
if constexpr(Ratio::num != 1 || Ratio::den != 1) {
auto txt = basic_fixed_string("[") + regular<Ratio::num>();
if constexpr(Ratio::den == 1) {
return txt + basic_fixed_string("]");
}
else {
return txt + basic_fixed_string("/") + regular<Ratio::den>() + basic_fixed_string("]");
}
}
else {
return basic_fixed_string("");
}
}
template<typename Ratio, typename PrefixType>
constexpr auto prefix_or_ratio_text()
{
if constexpr(Ratio::num != 1 || Ratio::den != 1) {
if constexpr (!std::same_as<PrefixType, no_prefix>) {
using prefix = downcast<detail::prefix_base<PrefixType, Ratio>>;
if constexpr(!std::same_as<prefix, prefix_base<PrefixType, Ratio>>) {
// print as a prefixed unit
return prefix::symbol;
}
else {
// print as a ratio of the coherent unit
return ratio_text<Ratio>();
}
}
else {
// print as a ratio of the coherent unit
return ratio_text<Ratio>();
}
}
}
template<bool Divide, std::size_t Idx>
constexpr auto operator_text()
{
if constexpr(Idx == 0) {
if constexpr(Divide) {
return basic_fixed_string("1/");
}
else {
return basic_fixed_string("");
}
}
else {
if constexpr(Divide) {
return basic_fixed_string("/");
}
else {
return basic_fixed_string("");
}
}
}
template<typename E, basic_fixed_string Symbol, std::size_t Idx>
constexpr auto exp_text()
{
// get calculation operator + symbol
const auto txt = operator_text<E::num < 0, Idx>() + Symbol;
if constexpr(E::den != 1) {
// add root part
return txt + basic_fixed_string("^(") + regular<abs(E::num)>() + basic_fixed_string("/") + regular<E::den>() + basic_fixed_string(")");
}
else if constexpr(abs(E::num) != 1) {
// add exponent part
return txt + superscript<abs(E::num)>();
}
else {
return txt;
}
}
template<typename Dim>
constexpr auto dimension_symbol()
{
if constexpr(BaseDimension<Dim>)
return Dim::symbol;
else
// coherent derived unit
return downcast<unit<Dim, ratio<1>>>::symbol;
}
template<typename... Es, std::size_t... Idxs>
constexpr auto base_symbol_text_impl(dimension<Es...>, std::index_sequence<Idxs...>)
{
return (exp_text<Es, dimension_symbol<typename Es::dimension>(), Idxs>() + ...);
}
template<typename... Es>
constexpr auto base_symbol_text(dimension<Es...> d)
{
return base_symbol_text_impl(d, std::index_sequence_for<Es...>());
}
template<typename... Es>
constexpr bool all_named(dimension<Es...>)
{
return (downcast<unit<typename Es::dimension, ratio<1>>>::is_named && ...);
}
template<typename Dim>
constexpr auto base_symbol_text()
{
using recipe = typename Dim::recipe;
if constexpr(all_named(recipe()))
return base_symbol_text(recipe());
else
return base_symbol_text(Dim());
}
template<typename E, typename U, std::size_t Idx>
constexpr auto exp_validate_and_text()
{
static_assert(same_dim<typename E::dimension, typename U::dimension>, "The order and number of units in `deduced_derived_unit<Us...>` should match dimensions provided in a `derived_dimension<>`");
return exp_text<E, U::symbol, Idx>();
}
template<typename... Us, typename... Es, std::size_t... Idxs>
constexpr auto deduced_symbol_text_impl(dimension<Es...>, std::index_sequence<Idxs...>)
{
return (exp_validate_and_text<Es, Us, Idxs>() + ...);
}
template<typename... Us, typename... Es>
constexpr auto deduced_symbol_text(dimension<Es...> d)
{
static_assert(sizeof...(Es) == sizeof...(Us), "The number of `deduced_derived_unit<Us...>` units should match the number of exponents provided to `derived_dimension<>`");
return deduced_symbol_text_impl<Us...>(d, std::index_sequence_for<Es...>());
}
template<typename Dim, typename... Us>
constexpr auto deduced_symbol_text()
{
if constexpr(are_units_of_base_dimension<Us...>)
return deduced_symbol_text<Us...>(typename Dim::base_type());
else
return deduced_symbol_text<Us...>(typename Dim::recipe());
}
template<typename Unit>
constexpr auto unit_text()
{
if constexpr(!is_unit<Unit>) {
// Unit is a downcasted derived unit child class already so just print defined symbol immediately
return Unit::symbol;
}
else {
// we are dealing with a non-user-defined unit here
using ratio = Unit::ratio;
using dim = Unit::dimension;
if constexpr(!is_dimension<dim>) {
// downcasted user-defined dimension
// print as a prefix or ratio of a coherent unit symbol defined by the user
using coherent_unit = downcast<units::unit<dim, units::ratio<1>>>;
return prefix_or_ratio_text<ratio, typename coherent_unit::prefix_type>() + coherent_unit::symbol;
}
else {
// print as a ratio of a coherent unit + coherent unit dimensions and their exponents
return ratio_text<ratio>() + base_symbol_text(dim{});
}
}
}
} // namespace detail
// derived_unit
template<typename Child, Dimension Dim, basic_fixed_string Symbol, PrefixType PT>
struct named_coherent_derived_unit : downcast_child<Child, unit<Dim, ratio<1>>> {
static constexpr bool is_named = true;
static constexpr auto symbol = Symbol;
using prefix_type = PT;
};
template<typename Child, Dimension Dim>
struct coherent_derived_unit : downcast_child<Child, unit<Dim, ratio<1>>> {
static constexpr bool is_named = false;
static constexpr auto symbol = detail::base_symbol_text<Dim>();
using prefix_type = no_prefix;
};
template<typename Child, Dimension Dim, basic_fixed_string Symbol, Ratio R, PrefixType PT = no_prefix>
struct named_scaled_derived_unit : downcast_child<Child, unit<Dim, R>> {
static constexpr bool is_named = true;
static constexpr auto symbol = Symbol;
using prefix_type = PT;
};
template<typename Child, Dimension Dim, basic_fixed_string Symbol, PrefixType PT, Unit U, Unit... Us>
struct named_deduced_derived_unit : downcast_child<Child, detail::deduced_derived_unit<Dim, U, Us...>> {
static constexpr bool is_named = true;
static constexpr auto symbol = Symbol;
using prefix_type = PT;
};
template<typename Child, Dimension Dim, Unit U, Unit... Us>
requires U::is_named && (Us::is_named && ... && true)
struct deduced_derived_unit : downcast_child<Child, detail::deduced_derived_unit<Dim, U, Us...>> {
static constexpr bool is_named = false;
static constexpr auto symbol = detail::deduced_symbol_text<Dim, U, Us...>();
using prefix_type = no_prefix;
};
template<typename Child, Prefix P, Unit U>
requires (!std::same_as<typename U::prefix_type, no_prefix>)
struct prefixed_derived_unit : downcast_child<Child, unit<typename U::dimension, ratio_multiply<typename P::ratio, typename U::ratio>>> {
static constexpr bool is_named = true;
static constexpr auto symbol = P::symbol + U::symbol;
using prefix_type = P::prefix_type;
};
// template<typename Child, Dimension Dim, basic_fixed_string Symbol, PrefixType PT, Unit U, Unit... Us>
// struct named_deduced_derived_unit : downcast_child<Child, detail::deduced_derived_unit<Dim, U, Us...>> {
// static constexpr bool is_named = true;
// static constexpr auto symbol = Symbol;
// using prefix_type = PT;
// };
} // namespace units

View File

@@ -22,4 +22,4 @@
add_subdirectory(unit_test/runtime)
add_subdirectory(unit_test/static)
add_subdirectory(metabench)
#add_subdirectory(metabench)

View File

@@ -131,7 +131,7 @@ namespace units {
struct dim_invert<dimension<Es...>> : std::type_identity<downcast_traits_t<dimension<exp_invert_t<Es>...>>> {};
template<Dimension D>
using dim_invert_t = dim_invert<typename D::base_type>::type;
using dim_invert_t = dim_invert<typename D::downcast_base_type>::type;
// make_dimension
@@ -196,7 +196,7 @@ namespace units {
struct dimension_multiply<dimension<E1...>, dimension<E2...>> : std::type_identity<downcast_traits_t<merge_dimension_t<dimension<E1...>, dimension<E2...>>>> {};
template<Dimension D1, Dimension D2>
using dimension_multiply_t = dimension_multiply<typename D1::base_type, typename D2::base_type>::type;
using dimension_multiply_t = dimension_multiply<typename D1::downcast_base_type, typename D2::downcast_base_type>::type;
// dimension_divide
@@ -209,6 +209,6 @@ namespace units {
};
template<Dimension D1, Dimension D2>
using dimension_divide_t = dimension_divide<typename D1::base_type, typename D2::base_type>::type;
using dimension_divide_t = dimension_divide<typename D1::downcast_base_type, typename D2::downcast_base_type>::type;
} // namespace units

View File

@@ -131,7 +131,7 @@ namespace units {
struct dim_invert<dimension<Es...>> : std::type_identity<downcast_traits_t<dimension<exp_invert_t<Es>...>>> {};
template<Dimension D>
using dim_invert_t = dim_invert<typename D::base_type>::type;
using dim_invert_t = dim_invert<typename D::downcast_base_type>::type;
// make_dimension
@@ -196,7 +196,7 @@ namespace units {
struct dimension_multiply<dimension<E1...>, dimension<E2...>> : std::type_identity<downcast_traits_t<merge_dimension_t<dimension<E1...>, dimension<E2...>>>> {};
template<Dimension D1, Dimension D2>
using dimension_multiply_t = dimension_multiply<typename D1::base_type, typename D2::base_type>::type;
using dimension_multiply_t = dimension_multiply<typename D1::downcast_base_type, typename D2::downcast_base_type>::type;
// dimension_divide
@@ -209,6 +209,6 @@ namespace units {
};
template<Dimension D1, Dimension D2>
using dimension_divide_t = dimension_divide<typename D1::base_type, typename D2::base_type>::type;
using dimension_divide_t = dimension_divide<typename D1::downcast_base_type, typename D2::downcast_base_type>::type;
} // namespace units

Some files were not shown because too many files have changed in this diff Show More