diff --git a/README.md b/README.md index 368dcd74..69d8987e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![AppVeyor](https://img.shields.io/appveyor/ci/mpusz/units/master.svg?label=AppVeyor)](https://ci.appveyor.com/project/mpusz/units) [![Download](https://api.bintray.com/packages/mpusz/conan-mpusz/mp-units%3Ampusz/images/download.svg) ](https://bintray.com/mpusz/conan-mpusz/mp-units%3Ampusz/_latestVersion) -# `units` - A Units Library for C++ +# `mp-units` - A Units Library for C++ ## Summary @@ -56,7 +56,7 @@ NOTE: This library as of now compiles correctly only with gcc-9.1 and newer. ## Release notes -- ??? +- 0.3.0 Sep 16, 2019 (CppCon 2019 release) - Applied the feedback from the Cologne evening session - `upcasting_traits` renamed to `downcasting_traits` - `Dimension` template parameter removed from quantity @@ -67,11 +67,18 @@ NOTE: This library as of now compiles correctly only with gcc-9.1 and newer. - Missing `operator*` added - Predefined dimensions moved to a dedicated directory - `dimension_` prefix removed from names of derived dimensions + - cmcstl2 library updated to 2019.09.19 + - `base_dimension` is a value provided as `const&` to the `exp` type + - integrated with Compiler Explorer + - gsl-lite deppendency removed + - Fractional dimension exponents support added + - `QuantityOf` concept introduced + - `quantity_cast()` support added - 0.2.0 July 18, 2019 - Added C++20 features supported by gcc-9.1 (std::remove_cvref_t, down with typename, std::type_identity) - The design as described on C++Now 2019 talk (https://youtu.be/wKchCktZPHU) - - Compile-time performance opimisations (type_list, common_ratio, ratio, conditional_t) + - Compile-time performance optimisations (type_list, common_ratio, ratio, conditional_t) - 0.1.0 May 18, 2019 - Initial library release diff --git a/doc/DESIGN.md b/doc/DESIGN.md index fdd42866..68b96297 100644 --- a/doc/DESIGN.md +++ b/doc/DESIGN.md @@ -1,4 +1,4 @@ -# `units` - Physical Units Library for C++ +# `mp-units` - A Units Library for C++ ## Summary @@ -30,12 +30,12 @@ static_assert(10km / 5km == 2); ## Approach 1. Safety and performance - - strong types - - compile-time safety - - `constexpr` all the things + - strong types + - compile-time safety + - `constexpr` all the things 2. The best possible user experience - - compiler errors - - debugging + - compiler errors + - debugging 3. No macros in the user interface 4. Easy extensibility 5. No external dependencies @@ -58,13 +58,13 @@ There are C++ concepts provided for each such quantity type: ```cpp template -concept Length = Quantity && std::same_as; +concept Length = QuantityOf; ``` With that we can easily write a function template like this: ```cpp -constexpr stde::units::Velocity auto avg_speed(units::Length auto d,stde::units::Time auto t) +constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t) { return d / t; } @@ -94,28 +94,28 @@ concept Dimension = #### `Exponents` -`units::exp` provides an information about a single base dimension and its exponent in a derived -dimension: +`units::exp` provides an information about a single base dimension and its (possibly fractional) +exponent in a derived dimension: ```cpp -template +template struct exp { - using dimension = BaseDimension; - static constexpr int value = Value; + static constexpr const base_dimension& dimension = BaseDimension; + static constexpr int num = Num; + static constexpr int den = Den; }; ``` -where `BaseDimension` is a unique sortable compile-time value and for now is implemented as: +where `BaseDimension` is a unique sortable compile-time value: ```cpp -template -using dim_id = std::integral_constant; +struct base_dimension { + const char* name; +}; +constexpr bool operator==(const base_dimension& lhs, const base_dimension& rhs); +constexpr bool operator<(const base_dimension& lhs, const base_dimension& rhs); ``` -but it is meant to be replaced with C++20 class `constexpr` values provided as non-type template -parameters (when feature will be available in a compiler) so that for example base dimension for -length will be expressed as `dimension>`. - `units::Exponent` concept is satisfied if provided type is an instantiation of `units::exp` class template: @@ -208,13 +208,32 @@ struct merge_dimension { ```cpp template - requires (R::num > 0) + requires (R::num * R::den > 0) struct unit : downcast_base> { using dimension = D; using ratio = R; }; ``` +For example to define the base unit of `length`: + +```cpp +struct metre : unit {}; +``` + +Also there are few alias templates provided as convenience helpers to simplify `Ratio` handling: +- units with prefixes + +```cpp +struct kilometre : kilo {}; +``` + +- derived units + +```cpp +struct kilometre_per_hour : derived_unit {}; +``` + `units::Unit` is a Concept that is satisfied by a type that is empty and publicly derived from `units::unit` class template: @@ -302,7 +321,17 @@ operation and provides it directly to `units::common_quantity_t` type trait. #### `quantity_cast` To explicitly force truncating conversions `quantity_cast` function is provided which is a direct -counterpart of `std::chrono::duration_cast`. +counterpart of `std::chrono::duration_cast`. As a template argument user can provide here either +a `quantity` type or only its template parameters (`Unit`, `Rep`): + +```cpp +template + requires std::same_as +constexpr To quantity_cast(const quantity& q); + +template +constexpr quantity quantity_cast(const quantity& q); +``` ## Strong types instead of aliases, and type downcasting capability @@ -429,87 +458,52 @@ template<> struct downcasting_traits> : downcast_to, exp> {}; -template<> struct downcasting_traits> : downcast_to {}; -``` + ```cpp + struct digital_information : units::make_dimension_t> {}; + template<> + struct units::downcasting_traits> : units::downcast_to {}; + ``` 2. Define a concept that will match a new dimension: -```cpp -template -concept Velocity = Quantity && std::same_as; -``` + ```cpp + template + concept DigitalInformation = units::QuantityOf; + ``` 3. Define units and provide downcasting traits for them: - - base unit + ```cpp + struct bit : units::unit {}; + template<> struct units::downcasting_traits> : units::downcast_to {}; + + struct byte : units::unit> {}; + template<> struct units::downcasting_traits> : units::downcast_to {}; + ``` -```cpp -struct metre : unit> {}; -template<> struct downcasting_traits> : downcast_to {}; -``` +4. Provide user-defined literals for the most important units: - - units with prefixes - -```cpp -struct kilometre : kilo {}; -template<> struct downcasting_traits> : downcast_to {}; -``` - - - derived units - -```cpp -struct kilometre_per_hour : derived_unit {}; -template<> struct downcasting_traits> : downcast_to {}; -``` - -5. Provide user-defined literals for the most important units: - -```cpp -inline namespace literals { - constexpr auto operator""_mps(unsigned long long l) { return quantity(l); } - constexpr auto operator""_mps(long double l) { return quantity(l); } - - constexpr auto operator""_kmph(unsigned long long l) { return quantity(l); } - constexpr auto operator""_kmph(long double l) { return quantity(l); } -} -``` - - -## Adding new base dimensions - -For now base dimensions are defined in terms of `std::integral_constant` and the provided -values must be unique. For example: - -```cpp -struct base_dim_length : dim_id<0> {}; -struct base_dim_mass : dim_id<1> {}; -struct base_dim_time : dim_id<2> {}; -struct base_dim_electric_current : dim_id<3> {}; -struct base_dim_temperature : dim_id<4> {}; -struct base_dim_amount_of_substance : dim_id<5> {}; -struct base_dim_luminous_intensity : dim_id<6> {}; -``` - -However, as soon as C++20 class type values will be supported as non-type template parameters -base dimensions will be just a text values. For example: - -```cpp -inline constexpr base_dim base_dim_length = "length"; -``` - -With that it should be really easy to add support for any new non-standard base units to the -library without the risk of collision with any dimension type defined by the library itself or -by other users extending the library with their own dimension types. - -Additionally, it should make the error logs even shorter thus easier to understand. + ```cpp + inline namespace literals { + constexpr auto operator""_b(unsigned long long l) { return units::quantity(l); } + constexpr auto operator""_b(long double l) { return units::quantity(l); } + + constexpr auto operator""_B(unsigned long long l) { return units::quantity(l); } + constexpr auto operator""_B(long double l) { return units::quantity(l); } + } + ``` ## Open questions