Skip to content

Commit

Permalink
Merge pull request #88 from bernedom/refactoring/move-unit_cast-to-ow…
Browse files Browse the repository at this point in the history
…n-include-file

Refactoring/move unit cast to own include file
  • Loading branch information
bernedom authored Mar 24, 2021
2 parents b490c65 + 2a52d29 commit 5163b08
Show file tree
Hide file tree
Showing 50 changed files with 278 additions and 209 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Changelog

## 2.0.5
## 2.1.0

* Fixed typos in documentation
* Moved helper function such as `unit_cast` and `unit_with_common_ratio` to own file for easier maintenance
* Moved cross-unit-operations and `epsEqual` to a separate file for easier maintenance
* Rename `epsEqual()` to `eps_equals()` for consitency with naming scheme

## 2.0.4

Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12)

project(
"SI"
VERSION 2.0.5
VERSION 2.1.0
DESCRIPTION
"A header only c++ library that provides type safety and user defined literals for handling pyhsical values defined in the International System of Units."
HOMEPAGE_URL "https://github.com/bernedom/SI"
Expand Down
2 changes: 1 addition & 1 deletion include/SI/absorbed_dose.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file is part of "SI" version 2.0.5
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
Expand Down
2 changes: 1 addition & 1 deletion include/SI/acceleration.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file is part of "SI" version 2.0.5
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
Expand Down
2 changes: 1 addition & 1 deletion include/SI/angle.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file is part of "SI" version 2.0.5
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
Expand Down
2 changes: 1 addition & 1 deletion include/SI/area.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file is part of "SI" version 2.0.5
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
Expand Down
2 changes: 1 addition & 1 deletion include/SI/astronomic.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file is part of "SI" version 2.0.5
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
Expand Down
2 changes: 1 addition & 1 deletion include/SI/catalytic_activity.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file is part of "SI" version 2.0.5
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
Expand Down
60 changes: 60 additions & 0 deletions include/SI/detail/cross_unit_operations.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
*
* https://github.com/bernedom/SI
*
* SPDX-License-Identifier: MIT
*
**/
#pragma once

#include "detail.h"

namespace SI::detail {
// forward declaration
template <char _symbol, typename _exponent, typename _type, typename _ratio>
struct unit_t;

/// divide a value of a certain unit with another value of a possibly
/// different type resulting in a new type, the resulting exponent is
/// specified by resulting unit using a variadic template to simplify usage of
/// implementation the internal type of the result is the internal type of lhs
template <template <typename...> typename _resulting_unit, typename _unit_lhs,
typename _unit_rhs>
constexpr auto cross_unit_divide(const _unit_lhs &lhs, const _unit_rhs &rhs) {
// do not use for the same unit as this should result in decreasing the
// exponent
static_assert(!std::is_same<_unit_lhs, _unit_rhs>::value);
static_assert(is_unit_t_v<_unit_lhs>, "lhs parameter is a unit_t");
static_assert(is_unit_t_v<_unit_rhs>, "rhs parameter is a unit_t");

using resulting_ratio = typename std::ratio_divide<typename _unit_lhs::ratio,
typename _unit_rhs::ratio>;
return _resulting_unit<typename _unit_lhs::internal_type, resulting_ratio>(
lhs.value() / rhs.value());
}
/// multiply a value of a unit witn another value of a possibly different
/// value resulting in a value of a new type with exponent 1 the internal type
/// of the result is the internal type of lhs
/// @todo add function that works with variable exponent units and remove
/// special typedefs for time

template <template <typename...> typename _resulting_unit, typename _unit_lhs,
typename _unit_rhs>
constexpr auto cross_unit_multiply(const _unit_lhs &lhs, const _unit_rhs &rhs) {
// do not use for the same unit as this should result in increasing the
// exponent
static_assert(!std::is_same<_unit_lhs, _unit_rhs>::value);
static_assert(is_unit_t_v<_unit_lhs>, "lhs parameter is a unit_t");
static_assert(is_unit_t_v<_unit_rhs>, "rhs parameter is a unit_t");
using resulting_ratio =
typename std::ratio_multiply<typename _unit_lhs::ratio,
typename _unit_rhs::ratio>;
return _resulting_unit<typename _unit_lhs::internal_type, resulting_ratio>(
lhs.value() * rhs.value());
}

} // namespace SI::detail
33 changes: 22 additions & 11 deletions include/SI/detail/detail.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file is part of "SI" version 2.0.5
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
Expand All @@ -13,11 +13,8 @@

#include "number_parser.h"
#include <cstdint>
#include <limits>
#include <numeric>
#include <ratio>
#include <stdexcept>
#include <type_traits>

/// Namespace containing implementation details for SI
namespace SI::detail {
Expand All @@ -31,13 +28,7 @@ struct is_ratio<std::ratio<_num, _den>> : std::true_type {};
template <typename _type>
inline constexpr bool is_ratio_v = is_ratio<_type>::value;

template <typename T, std::enable_if_t<std::is_floating_point_v<T>> * = nullptr>
constexpr bool epsEqual(const T &lhs, const T &rhs) {

return (lhs - rhs) < std::numeric_limits<T>::epsilon() &&
(lhs - rhs) > -std::numeric_limits<T>::epsilon();
// return std::abs(lhs - rhs) < std::numeric_limits<T>::epsilon();
}
/// calculate gcd for rations
template <typename _ratio_lhs, typename _ratio_rhs> struct ratio_gcd {
private:
using gcd_num = std::integral_constant<std::intmax_t,
Expand All @@ -53,4 +44,24 @@ template <typename _ratio_lhs, typename _ratio_rhs> struct ratio_gcd {
_ratio_rhs::den>;
};

// forward declaration
template <char _symbol, typename _exponent, typename _type, typename _ratio>
struct unit_t;

/// helper template to check if a type is a unit_t (false for all other
/// types)
template <typename _unit> struct is_unit_t : std::false_type {};

/// template specialisation to check if a type is a unit_t (true if unit_t)
template <char _symbol, typename _exponent, typename _ratio, typename _type>
struct is_unit_t<const unit_t<_symbol, _exponent, _type, _ratio>>
: std::true_type {};

/// non-const specialisation of check above
template <char _symbol, typename _exponent, typename _ratio, typename _type>
struct is_unit_t<unit_t<_symbol, _exponent, _type, _ratio>> : std::true_type {};

template <typename _type>
inline constexpr bool is_unit_t_v = is_unit_t<_type>::value;

} // namespace SI::detail
28 changes: 28 additions & 0 deletions include/SI/detail/eps_equal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
*
* https://github.com/bernedom/SI
*
* SPDX-License-Identifier: MIT
*
**/
#pragma once

#include <limits>
#include <numeric>
#include <type_traits>

namespace SI::detail {

template <typename T, std::enable_if_t<std::is_floating_point_v<T>> * = nullptr>
constexpr bool eps_equals(const T &lhs, const T &rhs) {

return (lhs - rhs) < std::numeric_limits<T>::epsilon() &&
(lhs - rhs) > -std::numeric_limits<T>::epsilon();
// return std::abs(lhs - rhs) < std::numeric_limits<T>::epsilon();
}

} // namespace SI::detail
2 changes: 1 addition & 1 deletion include/SI/detail/number_parser.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file is part of "SI" version 2.0.5
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
Expand Down
3 changes: 2 additions & 1 deletion include/SI/detail/operator_helpers.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file is part of "SI" version 2.0.5
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
Expand All @@ -11,6 +11,7 @@
**/
#pragma once

#include "cross_unit_operations.h"
#include "detail.h"

#define BUILD_UNIT_FROM_DIVISON(RESULTING_UNIT_T, DIVIDEND_UNIT_T, \
Expand Down
99 changes: 5 additions & 94 deletions include/SI/detail/unit.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file is part of "SI" version 2.0.5
* This file is part of "SI" version 2.1.0
* A header only c++ library that provides type safety and user defined literals
* for handling pyhsical values defined in the International System of
* Units
Expand All @@ -18,17 +18,15 @@
#endif

#include "detail.h"
#include "eps_equal.h"
#include "unit_cast.h"

#include <ratio>
#include <type_traits>

/// Namespace containing all SI units
namespace SI::detail {

// forward declarations
template <typename _target_type, typename _rhs_T>
constexpr auto unit_cast(const _rhs_T &rhs);

template <typename _unit_lhs, typename _unit_rhs> struct unit_with_common_ratio;

/// @todo add in-place unit_cast for move operators
Expand Down Expand Up @@ -168,8 +166,8 @@ struct unit_t {
return unit_cast<gcd_unit>(rhs).value() ==
unit_cast<gcd_unit>(*this).value();
} else {
return detail::epsEqual(unit_cast<gcd_unit>(rhs).value(),
unit_cast<gcd_unit>(*this).value());
return detail::eps_equals(unit_cast<gcd_unit>(rhs).value(),
unit_cast<gcd_unit>(*this).value());
}
}

Expand Down Expand Up @@ -499,91 +497,4 @@ operator/(const _type &lhs,
static_cast<_type>(_ratio::den)))});
}

/// helper template to check if a type is a unit_t (false for all other types)
template <typename _unit> struct is_unit_t : std::false_type {};

/// template specialisation to check if a type is a unit_t (true if unit_t)
template <char _symbol, typename _exponent, typename _ratio, typename _type>
struct is_unit_t<const unit_t<_symbol, _exponent, _type, _ratio>>
: std::true_type {};

/// non-const specialisation of check above
template <char _symbol, typename _exponent, typename _ratio, typename _type>
struct is_unit_t<unit_t<_symbol, _exponent, _type, _ratio>> : std::true_type {};

template <typename _type>
inline constexpr bool is_unit_t_v = is_unit_t<_type>::value;

/// function to cast between two units of the same type
template <typename _target_type, typename _rhs_T>
constexpr auto unit_cast(const _rhs_T &rhs) {
// using static assert instead of std::enable if in order to be able to
// forward declare this function easier
static_assert(
is_unit_t_v<_rhs_T> ||
std::is_base_of<
unit_t<_rhs_T::symbol::value, typename _rhs_T::exponent,
typename _rhs_T::internal_type, typename _rhs_T::ratio>,
_rhs_T>::value,
"is of type unit_t or a derived class");
using conversion_ratio =
std::ratio_divide<typename _rhs_T::ratio, typename _target_type::ratio>;

return _target_type(
((rhs.value() * conversion_ratio::num) / conversion_ratio::den));
}

template <typename _unit_lhs, typename _unit_rhs>
struct unit_with_common_ratio {
static_assert(is_unit_t_v<_unit_lhs>, "only supported for SI::unit_t");
static_assert(is_unit_t_v<_unit_rhs>, "only supported for SI::unit_t");
static_assert(std::is_convertible<typename _unit_lhs::internal_type,
typename _unit_rhs::internal_type>::value);
static_assert(_unit_lhs::symbol::value == _unit_rhs::symbol::value);
using type =
unit_t<_unit_lhs::symbol::value, typename _unit_lhs::exponent,
typename _unit_lhs::internal_type,
typename detail::ratio_gcd<typename _unit_lhs::ratio,
typename _unit_rhs::ratio>::ratio>;
};

/// divide a value of a certain unit with another value of a possibly
/// different type resulting in a new type, the resulting exponent is
/// specified by resulting unit using a variadic template to simplify usage of
/// implementation the internal type of the result is the internal type of lhs
template <template <typename...> typename _resulting_unit, typename _unit_lhs,
typename _unit_rhs>
constexpr auto cross_unit_divide(const _unit_lhs &lhs, const _unit_rhs &rhs) {
// do not use for the same unit as this should result in decreasing the
// exponent
static_assert(!std::is_same<_unit_lhs, _unit_rhs>::value);
static_assert(is_unit_t_v<_unit_lhs>, "lhs parameter is a unit_t");
static_assert(is_unit_t_v<_unit_rhs>, "rhs parameter is a unit_t");

using resulting_ratio = typename std::ratio_divide<typename _unit_lhs::ratio,
typename _unit_rhs::ratio>;
return _resulting_unit<typename _unit_lhs::internal_type, resulting_ratio>(
lhs.value() / rhs.value());
}
/// multiply a value of a unit witn another value of a possibly different
/// value resulting in a value of a new type with exponent 1 the internal type
/// of the result is the internal type of lhs
/// @todo add function that works with variable exponent units and remove
/// special typedefs for time

template <template <typename...> typename _resulting_unit, typename _unit_lhs,
typename _unit_rhs>
constexpr auto cross_unit_multiply(const _unit_lhs &lhs, const _unit_rhs &rhs) {
// do not use for the same unit as this should result in increasing the
// exponent
static_assert(!std::is_same<_unit_lhs, _unit_rhs>::value);
static_assert(is_unit_t_v<_unit_lhs>, "lhs parameter is a unit_t");
static_assert(is_unit_t_v<_unit_rhs>, "rhs parameter is a unit_t");
using resulting_ratio =
typename std::ratio_multiply<typename _unit_lhs::ratio,
typename _unit_rhs::ratio>;
return _resulting_unit<typename _unit_lhs::internal_type, resulting_ratio>(
lhs.value() * rhs.value());
}

} // namespace SI::detail
Loading

0 comments on commit 5163b08

Please sign in to comment.