diff --git a/.circleci/config.yml b/.circleci/config.yml index 839f279c..5cde4c5d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -27,8 +27,8 @@ jobs: - checkout - run: apt upgrade -y && apt update -y && apt install -y git - run: git submodule sync && git submodule update --init --recursive --remote - - run: chmod +x ./mitama_build.sh - - run: ./mitama_build.sh + - run: mkdir -p build && cd build && cmake .. && make -j5 && ctest 2>&1 | tee ./ctset.log + workflows: build: diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f1cefee..5bbf48d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,11 +4,12 @@ set(CMAKE_CXX_STANDARD 17) # ...C++17 set(CMAKE_CXX_STANDARD_REQUIRED ON) #...is required... set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++17 find_package(Threads REQUIRED) - +find_package(Boost 1.62.0 REQUIRED) ## Set our project name project(mitama-dimensional) include_directories( + PUBLIC ${Boost_INCLUDE_DIRS} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/mitama-cpp-result/include @@ -27,7 +28,6 @@ add_subdirectory(tests/basic-tests) add_subdirectory(tests/delta-tests) add_subdirectory(tests/derived-unit-tests) add_subdirectory(tests/format-io-tests) +add_subdirectory(tests/literal-tests) add_subdirectory(tests/math-tests) add_subdirectory(tests/nonsi-unit-tests) -add_subdirectory(tests/refinement-tests) -add_subdirectory(tests/static-quantity-tests) diff --git a/README.md b/README.md index 69e2e650..6ad28119 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ Please refer to the [document](https://loligothick.github.io/mitama-dimensional/ - pre defined SI derived units - **USER DEFINED DIMENSION** - formatted output -- dimensional refinement ## Examples @@ -99,31 +98,6 @@ int main() { } ``` -- [dimensional refinement](https://loligothick.github.io/mitama-dimensional/UserManual/dimensional-refinement/) - -```cpp -#include -#include -#include -#include -#include - -int main() { - namespace si = mitama::systems::si; - using mitama::accepts_for, mitama::sym::L; - - // width = 2 m - mitama::quantity_t width = 2; - // height = 3 mm - mitama::quantity_t height = 3; - // area = 6000 mm^2 - mitama::quantity_t area = accepts_for> |= width * height; - // ^~~~~~~~~~~~~~~~ - // refine for L^2 -} -``` - - - [user defined dimension example](https://loligothick.github.io/mitama-dimensional/UserManual/user-defined-dimension/) diff --git a/example/overview.cpp b/example/overview.cpp index 7f4e8bcd..93d9a7fe 100644 --- a/example/overview.cpp +++ b/example/overview.cpp @@ -5,7 +5,7 @@ #include #include #include -#include + #include #include #include diff --git a/include/dimensional/dimensional.hpp b/include/dimensional/dimensional.hpp new file mode 100644 index 00000000..8ae100ea --- /dev/null +++ b/include/dimensional/dimensional.hpp @@ -0,0 +1,63 @@ +#ifndef MITAMA_DIMENSIONAL_HPP +#define MITAMA_DIMENSIONAL_HPP +#include +#include +#include +#include +#include +#include +#include + +namespace mitama::mitamagic { +template +inline constexpr std::size_t dimension_count_v = + (static_cast(std::is_same_v) + + ... + std::size_t{}); // type count meta-function +} // namespace mitama::mitamagic + +namespace mitama { + +template < class > +struct si_base_units {}; + +template struct dimension_tag {}; + +template +struct dimensional_t : private Units::tag... // for Dimensional tags +{ + template < class T > + struct is_wildcard : std::is_same> {}; + // sanity check for duplicate + static_assert(std::conjunction_v == 1)>...>, + "same dimension is not allowed"); + // sanity check for system + static_assert(mitamagic::tlist_all_same_v< + mitamagic::tlist_remove_if_t>>, + "different units within a dimension"); + static constexpr std::size_t value = sizeof...(Units); + using system_type + = mitamagic::tlist_element_t<0, + std::conditional_t< + std::is_same_v< + mitamagic::type_list<>, + mitamagic::tlist_remove_if_t + > + >, + mitamagic::type_list>, + mitamagic::tlist_remove_if_t + > + > + >; +}; + +template +using make_dimensional_t = si_base_units>; + + +} // namespace mitama +#endif diff --git a/include/dimensional/quantity.hpp b/include/dimensional/quantity.hpp new file mode 100644 index 00000000..24d9ab55 --- /dev/null +++ b/include/dimensional/quantity.hpp @@ -0,0 +1,413 @@ +#ifndef MITAMA_DIMENSIONAL_QUANTITY_HPP +#define MITAMA_DIMENSIONAL_QUANTITY_HPP +#include +#include + +namespace mitama { + +template < class > +struct dimensionless_converter {}; + +template < template class Synonym, class T, class... B > +struct dimensionless_converter>, T, system>> { + operator T() const { return static_cast>, T> const*>(this)->value(); } +}; + + +// Into Trait +template < class Quantity > +class Into; + +template < template class Synonym, class T, class... Units, class... B > +class Into>, T, system>> { + quantity_t>, T, system> const& quantity_; +public: + constexpr explicit Into(quantity_t>, T, system> const& q): quantity_(q) {} + // explicitly deleted + Into() = delete; + Into(Into const&) = delete; + Into(Into&&) = delete; + Into& operator=(Into const&) = delete; + Into& operator=(Into&&) = delete; + + template < class To, + std::enable_if_t, + remove_dim_if_t>, T, system>>> + , bool> = false > + constexpr operator To() const { + return To(quantity_.value()); + } +}; + + +template < class To, class From > +inline constexpr std::enable_if_t, To> +dimensional_convert(From const& from) { + if constexpr (dimensional_ext::is_complete_type_v>){ + return To{::mitama::converter::convert(from)}; + } + else { + return To{::mitama::mitamagic::converted_value(from)}; + } +} + +} // namespace mitama + +namespace mitama { + +template class Synonym, class...Units, class... B> +class quantity_t>, T, system> + : public dimensionless_converter>, T>> +{ + T value_; +public: + using value_type = T; + using dimension_type = dimensional_t; + using system_type = system; + + constexpr quantity_t(): value_{} {} + + template < class Dimension, auto Value, + std::enable_if_t< + std::conjunction_v< + std::is_convertible, T>, + is_same_dimensional> + , bool> = false> + constexpr quantity_t(static_quantity_t) noexcept + : value_(Value) + {} + + template < template class Pred, + class Dimension, + class U, + std::enable_if_t< + std::conjunction_v< + std::is_convertible> + , bool> = false> + constexpr quantity_t(refined> refined_) noexcept + : quantity_t(refined_.get()) + {} + + template , + std::is_convertible> + , bool> = false> + constexpr quantity_t(U &&u) : value_(std::forward(u)) {} + + template , + std::negation>> + , bool> = false> + explicit constexpr quantity_t(U &&u) : value_{std::forward(u)} {} + + template + , bool> = false> + explicit constexpr quantity_t(std::in_place_t, Args&& ...args) + : value_(std::forward(args)...) {} + + template , Args&&...> + , bool> = false> + constexpr explicit quantity_t(std::in_place_t, std::initializer_list il, Args&&... args) + : value_(il, std::forward(args)...) {} + + template < + class D, class U, class S, + std::enable_if_t> && + std::is_constructible_v && + std::is_convertible_v, + bool> = false> + constexpr quantity_t(quantity_t const &o) + : value_(mitamagic::converted_value(o)) {} + + template < + class D, class U, class S, + std::enable_if_t> && + std::is_constructible_v && + !std::is_convertible_v, + bool> = false> + explicit constexpr quantity_t(quantity_t const &o) + : value_{mitamagic::converted_value(o)} {} + + template < + class D, class U, class S, + std::enable_if_t, quantity_t>> && + std::is_constructible_v && + std::is_convertible_v, + bool> = false> + constexpr quantity_t(quantity_t const &o) + : value_(::mitama::converter, quantity_t>::convert(o)) {} + + template < + class D, class U, class S, + std::enable_if_t, quantity_t>> && + std::is_constructible_v && + !std::is_convertible_v, + bool> = false> + explicit constexpr quantity_t(quantity_t const &o) + : value_{::mitama::converter, quantity_t>::convert(o)} {} + + template < + class D, class U, class S, + std::enable_if_t> && + std::is_convertible_v, + bool> = false> + constexpr quantity_t &operator=(quantity_t const &o) & { + this->value_ = mitamagic::converted_value(o); + return *this; + } + + template < + class D, class U, class S, + std::enable_if_t, quantity_t>> && + std::is_convertible_v, + bool> = false> + constexpr quantity_t &operator=(quantity_t const &o) & { + this->value_ = ::mitama::converter, quantity_t>::convert(o); + return *this; + } + + constexpr T value() const { return value_; } + + template < class F > + constexpr auto validate(F&& validator) const & { + return std::forward(validator)(*this); + } + template < class F > + constexpr auto validate(F&& validator) && { + return std::forward(validator)(std::move(*this)); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + dimensional_ext::is_complete_type<::mitama::converter, quantity_t>>, + dimensional_ext::is_greater_or_equal_comparable_with> + , bool> = false> + constexpr bool operator==(quantity_t const &o) const { + return this->value_ == ::mitama::converter, quantity_t>::convert(o); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + is_same_dimensional>, + dimensional_ext::is_greater_or_equal_comparable_with> + , bool> = false> + constexpr bool operator==(quantity_t const &o) const { + auto [l, r] = mitamagic::scaler::dimension_type>::template value>(); + return l * this->value() == r * o.value(); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + dimensional_ext::is_complete_type<::mitama::converter, quantity_t>>, + dimensional_ext::is_notequal_comparable_with> + , bool> = false> + constexpr bool operator!=(quantity_t const &o) const { + return this->value_ != ::mitama::converter, quantity_t>::convert(o); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + is_same_dimensional>, + dimensional_ext::is_notequal_comparable_with> + , bool> = false> + constexpr bool operator!=(quantity_t const &o) const { + auto [l, r] = mitamagic::scaler::dimension_type>::template value>(); + return l * this->value() != r * o.value(); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + dimensional_ext::is_complete_type<::mitama::converter, quantity_t>>, + dimensional_ext::is_less_comparable_with> + , bool> = false> + constexpr bool operator<(quantity_t const &o) const { + return this->value_ < ::mitama::converter, quantity_t>::convert(o); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + is_same_dimensional>, + dimensional_ext::is_less_comparable_with> + , bool> = false> + constexpr bool operator<(quantity_t const &o) const { + auto [l, r] = mitamagic::scaler::dimension_type>::template value>(); + return l * this->value() < r * o.value(); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + dimensional_ext::is_complete_type<::mitama::converter, quantity_t>>, + dimensional_ext::is_less_or_equal_comparable_with> + , bool> = false> + constexpr bool operator<=(quantity_t const &o) const { + return this->value_ <= ::mitama::converter, quantity_t>::convert(o); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + is_same_dimensional>, + dimensional_ext::is_less_or_equal_comparable_with> + , bool> = false> + constexpr bool operator<=(quantity_t const &o) const { + auto [l, r] = mitamagic::scaler::dimension_type>::template value>(); + return l * this->value() <= r * o.value(); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + dimensional_ext::is_complete_type<::mitama::converter, quantity_t>>, + dimensional_ext::is_greater_comparable_with> + , bool> = false> + constexpr bool operator>(quantity_t const &o) const { + return this->value_ > ::mitama::converter, quantity_t>::convert(o); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + is_same_dimensional>, + dimensional_ext::is_greater_comparable_with> + , bool> = false> + constexpr bool operator>(quantity_t const &o) const { + auto [l, r] = mitamagic::scaler::dimension_type>::template value>(); + return l * this->value() > r * o.value(); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + dimensional_ext::is_complete_type<::mitama::converter, quantity_t>>, + dimensional_ext::is_greater_or_equal_comparable_with> + , bool> = false> + constexpr bool operator>=(quantity_t const &o) const { + return this->value_ >= ::mitama::converter, quantity_t>::convert(o); + } + + template < + class D, class U, + std::enable_if_t< + std::conjunction_v< + is_same_dimensional>, + dimensional_ext::is_greater_or_equal_comparable_with> + , bool> = false> + constexpr bool operator>=(quantity_t const &o) const { + auto [l, r] = mitamagic::scaler::dimension_type>::template value>(); + return l * this->value() >= r * o.value(); + } + + auto operator-() const { + if constexpr (std::is_integral_v) { + return quantity_t>, decltype(-std::declval()), system>{ -value_ }; + } + else { + return quantity_t{ -value_ }; + } + } + auto operator+() const { + if constexpr (std::is_integral_v) { + return quantity_t>, decltype(+std::declval()), system>{ +value_ }; + } + else { + return quantity_t{ +value_ }; + } + } + + Into into() const& { + return Into(*this); + } +}; + +template < class Dim, auto Value > +quantity_t(static_quantity_t) -> quantity_t; + +template < template class Pred, class Dim, class T > +quantity_t(refined>) -> quantity_t; + +namespace mitamagic { +template struct into_dimensional; + +template struct into_dimensional> { + using type = si_base_units>>; +}; + +template struct into_dimensional> { + using type = si_base_units>; +}; + +template class Synonym, class... Units> struct into_dimensional>> { + using type = Synonym>; +}; + +template +using into_dimensional_t = typename into_dimensional::type; +} // namespace mitamagic + +} // namespace mitama + +namespace mitama { + +template , is_dimensional_quantifier> + , bool> = false> +constexpr mitamagic::quotient_t, + mitamagic::into_dimensional_t> +operator*(U1, U2) { + return {}; +} + +template , is_dimensional_quantifier>, bool> = + false> +constexpr mitamagic::quotient_t< + mitamagic::into_dimensional_t, + mitamagic::inverse_t>> +operator/(U1, U2) { + return {}; +} + +template