diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dd89d06..f090756a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,4 +43,4 @@ enable_testing() add_subdirectory(test) # add usage example -add_subdirectory(example) +#add_subdirectory(example) diff --git a/conanfile.py b/conanfile.py index baa8d27b..44002a0f 100644 --- a/conanfile.py +++ b/conanfile.py @@ -6,13 +6,8 @@ class UnitConan(ConanFile): author = "Mateusz Pusz" license = "https://github.com/mpusz/units/blob/master/LICENSE" url = "https://github.com/mpusz/units" - description = "Physical Units library implementation for C++" + description = "Physical Units library for C++" settings = "os", "compiler", "build_type", "arch" - build_requires = ( - "gtest/1.8.0@bincrafters/stable" - ) - default_options = "gtest:shared=False" - generators = "cmake_paths" def build(self): cmake = CMake(self) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 209d56af..629fa2a0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,7 +47,7 @@ add_library(units INTERFACE) # include/units/bits/quantity.h # include/units/bits/tools.h #) -target_compile_features(units INTERFACE cxx_std_17) +target_compile_features(units INTERFACE cxx_std_20) target_include_directories(units INTERFACE $ diff --git a/src/include/units/bits/stdconcepts.h b/src/include/units/bits/stdconcepts.h new file mode 100644 index 00000000..5735dd24 --- /dev/null +++ b/src/include/units/bits/stdconcepts.h @@ -0,0 +1,44 @@ +// 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 +#include + +namespace mp { + + namespace detail { + template + bool concept SameHelper = std::is_same_v; + } + + template + bool concept Same = detail::SameHelper && detail::SameHelper; + + template + bool concept ConvertibleTo = std::is_convertible_v && + requires(From (&f)()) { + static_cast(f()); + }; + +} // namespace mp diff --git a/src/include/units/bits/tools.h b/src/include/units/bits/tools.h index e4c4cd3b..9e74ee32 100644 --- a/src/include/units/bits/tools.h +++ b/src/include/units/bits/tools.h @@ -22,16 +22,12 @@ #pragma once +#include "stdconcepts.h" #include #include namespace mp { - // Requires - - template - using Requires = std::enable_if_t; - // static_sign template @@ -60,6 +56,8 @@ namespace mp { // is_ratio + namespace detail { + template struct is_ratio : std::false_type { }; @@ -68,17 +66,22 @@ namespace mp { struct is_ratio> : std::true_type { }; + } + + template + bool concept Ratio = detail::is_ratio::value; + // common_ratio // todo: simplified - template + template struct common_ratio { using gcd_num = static_gcd; using gcd_den = static_gcd; using type = std::ratio; }; - template + template using common_ratio_t = typename common_ratio::type; } // namespace mp diff --git a/src/include/units/bits/type_list.h b/src/include/units/bits/type_list.h index 90c39081..da2bc7da 100644 --- a/src/include/units/bits/type_list.h +++ b/src/include/units/bits/type_list.h @@ -32,9 +32,22 @@ namespace mp { template struct type_list; + namespace detail { + + template + struct is_type_list : std::false_type {}; + + template + struct is_type_list> : std::true_type {}; + + } + + template + bool concept TypeList = detail::is_type_list::value; + // push_front - template + template struct type_list_push_front; template @@ -42,12 +55,12 @@ namespace mp { using type = type_list; }; - template - using type_list_push_front_t = typename type_list_push_front::type; + template + using type_list_push_front_t = typename type_list_push_front::type; // push_back - template + template struct type_list_push_back; template @@ -55,8 +68,8 @@ namespace mp { using type = type_list; }; - template - using type_list_push_back_t = typename type_list_push_back::type; + template + using type_list_push_back_t = typename type_list_push_back::type; // split @@ -76,17 +89,18 @@ namespace mp { using base = split_impl; using base_first = typename base::first_list; using base_second = typename base::second_list; - using first_list = std::conditional_t < Idx, base_first>; - using second_list = std::conditional_t < Idx>; + using first_list = std::conditional_t, base_first>; + using second_list = std::conditional_t>; }; } // namespace detail - template + template struct type_list_split; template struct type_list_split, N> { + static_assert(N <= sizeof...(Types), "Invalid index provided"); using split = detail::split_impl<0, N, Types...>; using first_list = typename split::first_list; using second_list = typename split::second_list; @@ -94,7 +108,7 @@ namespace mp { // split_half - template + template struct type_list_split_half; template @@ -103,11 +117,11 @@ namespace mp { // merge_sorted - template typename Pred> + template typename Pred> struct type_list_merge_sorted; - template typename Pred> - using type_list_merge_sorted_t = typename type_list_merge_sorted::type; + template typename Pred> + using type_list_merge_sorted_t = typename type_list_merge_sorted::type; template typename Pred> struct type_list_merge_sorted, type_list<>, Pred> { @@ -132,7 +146,7 @@ namespace mp { // sort - template typename Pred> + template typename Pred> struct type_list_sort; template typename Pred> @@ -154,7 +168,7 @@ namespace mp { using type = type_list_merge_sorted_t; }; - template typename Pred> - using type_list_sort_t = typename type_list_sort::type; + template typename Pred> + using type_list_sort_t = typename type_list_sort::type; } // namespace mp \ No newline at end of file diff --git a/src/include/units/dimension.h b/src/include/units/dimension.h index e5c5dbba..092573d8 100644 --- a/src/include/units/dimension.h +++ b/src/include/units/dimension.h @@ -35,7 +35,7 @@ namespace units { // dim_id_less template - struct dim_id_less : std::bool_constant { + struct dim_id_less : std::bool_constant { }; // exp @@ -46,15 +46,30 @@ namespace units { static constexpr int value = Value; }; + // is_exp + namespace detail { + template + struct is_exp : std::false_type { + }; + + template + struct is_exp> : std::true_type { + }; + } + + template + bool concept Exp = detail::is_exp::value; + + // exp_less - template + template struct exp_less : dim_id_less { }; // exp_invert - template + template struct exp_invert; template @@ -62,88 +77,96 @@ namespace units { using type = exp; }; - template + template using exp_invert_t = typename exp_invert::type; // dimension - template + template using dimension = mp::type_list; + // is_dimension + namespace detail { + template + struct is_dimension : std::false_type {}; + + template + struct is_dimension> : std::bool_constant<(is_exp::value && ...)> {}; + } + + template + bool concept Dimension = detail::is_dimension::value; + + // make_dimension namespace detail { - struct scalar; - - template + template struct dim_consolidate; - template + template using dim_consolidate_t = typename dim_consolidate::type; template<> struct dim_consolidate> { - using type = dimension; + using type = dimension<>; }; - template - struct dim_consolidate> { - using type = dimension; + template + struct dim_consolidate> { + using type = dimension; }; - template - struct dim_consolidate> { - using type = dim_consolidate_t>; + template + struct dim_consolidate> { + using rest = dim_consolidate_t>; + using type = std::conditional_t>, dimension, + mp::type_list_push_front_t>; }; - template + template struct dim_consolidate, exp, ERest...>> { using type = std::conditional_t>, dim_consolidate_t, ERest...>>>; }; - template - struct dim_consolidate> { - using rest = dim_consolidate_t>; - using type = std::conditional_t>, dimension, - mp::type_list_push_front_t>; - }; - } // namespace detail - template + template struct make_dimension { - using type = detail::dim_consolidate_t, exp_less>>; + using type = detail::dim_consolidate_t, exp_less>>; }; - template + template using make_dimension_t = typename make_dimension::type; + + // dimension_multiply - template + template struct dimension_multiply; - template + template struct dimension_multiply, dimension> { using type = make_dimension_t; }; - template + template using dimension_multiply_t = typename dimension_multiply::type; // dimension_divide - template + template struct dimension_divide; - template + template struct dimension_divide, dimension> : dimension_multiply, dimension...>> { }; - template + template using dimension_divide_t = typename dimension_divide::type; } // namespace units diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index 54480c24..82123b0a 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -28,23 +28,26 @@ namespace units { - template - class quantity; - // is_quantity + template + class quantity; + namespace detail { template struct is_quantity : std::false_type { }; - template + template struct is_quantity> : std::true_type { }; } + template + bool concept Quantity = detail::is_quantity::value; + // treat_as_floating_point template @@ -57,9 +60,9 @@ namespace units { namespace detail { - template + template struct quantity_cast_impl { - template + template static constexpr To cast(const quantity& q) { return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num) / @@ -67,27 +70,27 @@ namespace units { } }; - template + template struct quantity_cast_impl { - template + template static constexpr To cast(const quantity& q) { return To(static_cast(q.count())); } }; - template + template struct quantity_cast_impl { - template + template static constexpr To cast(const quantity& q) { return To(static_cast(static_cast(q.count()) / static_cast(CRatio::den))); } }; - template + template struct quantity_cast_impl { - template + template static constexpr To cast(const quantity& q) { return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num))); @@ -96,8 +99,8 @@ namespace units { } // namespace detail - template::value && std::is_same_v> = true> + template + requires mp::Same constexpr To quantity_cast(const quantity& q) { using c_ratio = std::ratio_divide; @@ -117,7 +120,7 @@ namespace units { // quantity - template> + template> class quantity { Rep value_; public: @@ -126,21 +129,20 @@ namespace units { using ratio = Ratio; static_assert(!detail::is_quantity::value, "rep cannot be a quantity"); - static_assert(mp::is_ratio::value, "ratio must be a specialization of std::ratio"); static_assert(ratio::num > 0, "ratio must be positive"); quantity() = default; quantity(const quantity&) = default; - template && - (treat_as_floating_point_v || !treat_as_floating_point_v)> = true> + template + requires mp::ConvertibleTo && (treat_as_floating_point_v || !treat_as_floating_point_v) constexpr explicit quantity(const Rep2& r) : value_{static_cast(r)} { } - template || - (std::ratio_divide::den == 1 && !treat_as_floating_point::value)> = true> + template + requires mp::ConvertibleTo && (treat_as_floating_point_v || + (std::ratio_divide::den == 1 && !treat_as_floating_point_v)) constexpr quantity(const quantity& q) : value_{quantity_cast(q).count()} { } @@ -208,7 +210,7 @@ namespace units { }; // clang-format off - template + template std::common_type_t, quantity> constexpr operator+(const quantity& lhs, const quantity& rhs) @@ -217,7 +219,7 @@ namespace units { return ret(ret(lhs).count() + ret(rhs).count()); } - template + template std::common_type_t, quantity> constexpr operator-(const quantity& lhs, const quantity& rhs) @@ -226,7 +228,7 @@ namespace units { return ret(ret(lhs).count() - ret(rhs).count()); } - template + template quantity, Ratio> constexpr operator*(const quantity& q, const Rep2& v) @@ -235,7 +237,7 @@ namespace units { return ret(ret(q).count() * v); } - template + template quantity, Ratio> constexpr operator*(const Rep1& v, const quantity& q) @@ -243,8 +245,8 @@ namespace units { return q * v; } - template> || std::ratio_multiply::den == 1> = true> + template + requires treat_as_floating_point_v> || std::ratio_multiply::den == 1 quantity, std::common_type_t, std::ratio_multiply> constexpr operator*(const quantity& lhs, const quantity& rhs) @@ -253,7 +255,7 @@ namespace units { return ret(lhs.count() * rhs.count()); } - template + template quantity>, std::common_type_t, Ratio> constexpr operator/(const Rep1& v, const quantity, Rep2, Ratio>& q) @@ -263,7 +265,7 @@ namespace units { return ret(v / den(q).count()); } - template + template quantity, Ratio> constexpr operator/(const quantity& q, const Rep2& v) @@ -272,7 +274,7 @@ namespace units { return ret(ret(q).count() / v); } - template + template std::common_type_t constexpr operator/(const quantity& lhs, const quantity& rhs) @@ -281,8 +283,8 @@ namespace units { return cq(lhs).count() / cq(rhs).count(); } - template> || std::ratio_divide::den == 1> = true> + template + requires treat_as_floating_point_v> || std::ratio_divide::den == 1 quantity, std::common_type_t, std::ratio_divide> constexpr operator/(const quantity& lhs, const quantity& rhs) @@ -291,7 +293,7 @@ namespace units { return ret(lhs.count() / rhs.count()); } - template + template quantity, Ratio> constexpr operator%(const quantity& q, const Rep2& v) @@ -300,7 +302,7 @@ namespace units { return ret(ret(q).count() % v); } - template + template std::common_type_t, quantity> constexpr operator%(const quantity& lhs, const quantity& rhs) @@ -309,7 +311,9 @@ namespace units { return ret(ret(lhs).count() % ret(rhs).count()); } - template + // clang-format on + + template constexpr bool operator==(const quantity& lhs, const quantity& rhs) { @@ -317,14 +321,14 @@ namespace units { return ct(lhs).count() == ct(rhs).count(); } - template + template constexpr bool operator!=(const quantity& lhs, const quantity& rhs) { return !(lhs == rhs); } - template + template constexpr bool operator<(const quantity& lhs, const quantity& rhs) { @@ -332,34 +336,33 @@ namespace units { return ct(lhs).count() < ct(rhs).count(); } - template + template constexpr bool operator<=(const quantity& lhs, const quantity& rhs) { return !(rhs < lhs); } - template + template constexpr bool operator>(const quantity& lhs, const quantity& rhs) { return rhs < lhs; } - template + template constexpr bool operator>=(const quantity& lhs, const quantity& rhs) { return !(lhs < rhs); } - // clang-format on } // namespace units namespace std { // todo: simplified - template + template struct common_type, units::quantity> { using type = units::quantity, mp::common_ratio_t>; diff --git a/src/include/units/si/base_dimensions.h b/src/include/units/si/base_dimensions.h index 2a95d98d..6b22f5e5 100644 --- a/src/include/units/si/base_dimensions.h +++ b/src/include/units/si/base_dimensions.h @@ -23,7 +23,6 @@ #pragma once #include "../dimension.h" -#include "../quantity.h" namespace units { diff --git a/src/include/units/si/length.h b/src/include/units/si/length.h index 29e40049..58a0a892 100644 --- a/src/include/units/si/length.h +++ b/src/include/units/si/length.h @@ -23,6 +23,7 @@ #pragma once #include "base_dimensions.h" +#include "../quantity.h" namespace units { diff --git a/src/include/units/si/time.h b/src/include/units/si/time.h index db01847a..f1255623 100644 --- a/src/include/units/si/time.h +++ b/src/include/units/si/time.h @@ -23,6 +23,7 @@ #pragma once #include "base_dimensions.h" +#include "../quantity.h" namespace units { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4220865d..112dc8b5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -37,16 +37,16 @@ if(NOT TARGET mp::units) endif() # unit tests -add_executable(unit_tests +add_library(unit_tests test_dimension.cpp test_quantity.cpp + test_tools.cpp test_type_list.cpp test_units.cpp ) target_link_libraries(unit_tests PRIVATE mp::units - GTest::Main ) add_test(NAME units.unit_tests COMMAND diff --git a/test/test_dimension.cpp b/test/test_dimension.cpp index 8607d264..dd09d602 100644 --- a/test/test_dimension.cpp +++ b/test/test_dimension.cpp @@ -21,7 +21,6 @@ // SOFTWARE. #include "units/dimension.h" -#include #include using namespace units; @@ -30,36 +29,44 @@ namespace { template using e = exp, Value>; -} -// make_dimension + // exp_invert -static_assert(std::is_same_v>, dimension>>); -static_assert(std::is_same_v, e<1, 1>>, dimension, e<1, 1>>>); -static_assert(std::is_same_v, e<0, 1>>, dimension, e<1, 1>>>); -static_assert(std::is_same_v, e<1, 1>>, dimension>>); -static_assert(std::is_same_v, e<1, -1>>, dimension>); + static_assert(std::is_same_v>, e<0, -1>>); + static_assert(std::is_same_v>, e<1, 1>>); -static_assert(std::is_same_v, e<1, 1>, e<0, 1>, e<1, 1>>, dimension, e<1, 2>>>); -static_assert(std::is_same_v, e<1, -1>, e<0, -1>, e<1, -1>>, dimension, e<1, -2>>>); + // make_dimension -static_assert(std::is_same_v, e<1, 1>, e<1, -1>>, dimension>>); -static_assert(std::is_same_v, e<0, -1>, e<1, 1>>, dimension>>); -static_assert(std::is_same_v, e<1, 1>, e<0, -1>>, dimension>>); -static_assert(std::is_same_v, e<1, 1>, e<0, -1>, e<1, -1>>, dimension>); + static_assert(std::is_same_v>, dimension>>); + static_assert(std::is_same_v, e<1, 1>>, dimension, e<1, 1>>>); + static_assert(std::is_same_v, e<0, 1>>, dimension, e<1, 1>>>); + static_assert(std::is_same_v, e<1, 1>>, dimension>>); + static_assert(std::is_same_v, e<1, -1>>, dimension<>>); -// dimension_multiply + static_assert(std::is_same_v, e<1, 1>, e<0, 1>, e<1, 1>>, dimension, e<1, 2>>>); + static_assert( + std::is_same_v, e<1, -1>, e<0, -1>, e<1, -1>>, dimension, e<1, -2>>>); -static_assert( - std::is_same_v>, dimension>>, dimension, e<1, 1>>>); -static_assert(std::is_same_v, e<1, 1>, e<2, 1>>, dimension>>, - dimension, e<1, 1>, e<2, 1>, e<3, 1>>>); -static_assert(std::is_same_v, e<1, 1>, e<2, 1>>, dimension>>, - dimension, e<1, 2>, e<2, 1>>>); -static_assert(std::is_same_v, e<1, 1>, e<2, 1>>, dimension>>, - dimension, e<2, 1>>>); + static_assert(std::is_same_v, e<1, 1>, e<1, -1>>, dimension>>); + static_assert(std::is_same_v, e<0, -1>, e<1, 1>>, dimension>>); + static_assert(std::is_same_v, e<1, 1>, e<0, -1>>, dimension>>); + static_assert(std::is_same_v, e<1, 1>, e<0, -1>, e<1, -1>>, dimension<>>); -// dimension_divide + // dimension_multiply -static_assert(std::is_same_v>, dimension>>, dimension, e<1, -1>>>); -static_assert(std::is_same_v>, dimension>>, dimension>); + static_assert( + std::is_same_v>, dimension>>, dimension, e<1, 1>>>); + static_assert(std::is_same_v, e<1, 1>, e<2, 1>>, dimension>>, + dimension, e<1, 1>, e<2, 1>, e<3, 1>>>); + static_assert(std::is_same_v, e<1, 1>, e<2, 1>>, dimension>>, + dimension, e<1, 2>, e<2, 1>>>); + static_assert(std::is_same_v, e<1, 1>, e<2, 1>>, dimension>>, + dimension, e<2, 1>>>); + + // dimension_divide + + static_assert( + std::is_same_v>, dimension>>, dimension, e<1, -1>>>); + static_assert(std::is_same_v>, dimension>>, dimension<>>); + +} // namespace diff --git a/test/test_quantity.cpp b/test/test_quantity.cpp index d4154d69..4793c141 100644 --- a/test/test_quantity.cpp +++ b/test/test_quantity.cpp @@ -21,153 +21,254 @@ // SOFTWARE. #include "units/si/velocity.h" -#include #include using namespace units; using namespace units::literals; +namespace { + template + class my_value { + T data_{}; + + public: + my_value() = default; + constexpr my_value(T v) : data_{v} {} + constexpr operator T() const { return data_; } + }; + +} // namespace + +namespace units { + + template + struct treat_as_floating_point> : std::is_floating_point { + }; + + template + struct quantity_values> { + static constexpr my_value zero() { return my_value(0); } + static constexpr my_value max() { return std::numeric_limits::max(); } + static constexpr my_value min() { return std::numeric_limits::lowest(); } + }; + +} // namespace units + +namespace std { + + template + struct common_type, U> : common_type { + }; + + template + struct common_type> : common_type { + }; + +} // namespace std + +namespace { + + using namespace units; + using namespace units::literals; + + // class invariants + + // constexpr quantity> error(0_m); // should trigger a static_assert + // constexpr quantity error(0); // should trigger a static_assert + // constexpr quantity> error(0); // should trigger a static_assert + + // member types + + static_assert(std::is_same_v::rep, int>); + static_assert(std::is_same_v::rep, float>); + static_assert(std::is_same_v::ratio, std::ratio<1, 1>>); + static_assert(std::is_same_v::ratio, std::ratio<1000, 1>>); + + // constructors + + static_assert(meters().count() == 0); + constexpr meters kilometer{1000}; + static_assert(kilometer.count() == 1000); + static_assert(meters(kilometer).count() == kilometer.count()); + + static_assert(meters(1).count() == 1); + static_assert(meters(my_value(1)).count() == 1); + static_assert(meters>(1).count() == 1); + // static_assert(meters(1.0).count() == 1); // should not compile + // static_assert(meters(my_value(1.0)).count() == 1); // should not compile + // static_assert(meters>(1.0).count() == 1); // should not compile + static_assert(meters(1.0).count() == 1.0); + static_assert(meters(my_value(1.0)).count() == 1.0); + static_assert(meters(1).count() == 1.0); + static_assert(meters(my_value(1)).count() == 1.0); + static_assert(meters(3.14f).count() == 3.14f); + static_assert(meters>(1.0).count() == 1.0); + static_assert(meters>(1).count() == 1.0); + static_assert(meters>(3.14f).count() == 3.14f); + + static_assert(meters(kilometer).count() == 1000); + // static_assert(meters(meters(3.14)).count() == 3); // should not compile + static_assert(meters(quantity_cast>(3.14_m)).count() == 3); + // static_assert(meters(meters>(1000.0)).count() == 1000); // should not compile + // static_assert(meters>(1000.0_m).count() == 1000); // should not compile + static_assert(meters(1000.0_m).count() == 1000.0); + static_assert(meters(meters>(1000.0)).count() == 1000.0); + static_assert(meters>(1000.0_m).count() == 1000.0); + static_assert(meters(kilometer).count() == 1000.0); + static_assert(meters>(kilometer).count() == 1000.0); + static_assert(meters(1_km).count() == 1000); + // static_assert(meters(1_s).count() == 1); // should not compile + // static_assert(kilometers(1010_m).count() == 1); // should not compile + static_assert(kilometers(quantity_cast>(1010_m)).count() == 1); + + // assignment operator + + static_assert([]() { + meters l1(1), l2(2); + return l2 = l1; + }() + .count() == 1); + + // static member functions + + static_assert(meters::zero().count() == 0); + static_assert(meters::min().count() == std::numeric_limits::lowest()); + static_assert(meters::max().count() == std::numeric_limits::max()); + static_assert(meters::zero().count() == 0.0); + static_assert(meters::min().count() == std::numeric_limits::lowest()); + static_assert(meters::max().count() == std::numeric_limits::max()); + static_assert(meters>::zero().count() == 0); + static_assert(meters>::min().count() == std::numeric_limits::lowest()); + static_assert(meters>::max().count() == std::numeric_limits::max()); + static_assert(meters>::zero().count() == 0.0); + static_assert(meters>::min().count() == std::numeric_limits::lowest()); + static_assert(meters>::max().count() == std::numeric_limits::max()); + + // unary member operators + + static_assert((+kilometer).count() == 1000); + static_assert((-kilometer).count() == -1000); + static_assert((+(-kilometer)).count() == -1000); + static_assert((-(-kilometer)).count() == 1000); + + // binary member operators + + static_assert([](auto v) { + auto vv = v++; + return std::make_pair(v, vv); + }(kilometer) == std::make_pair(meters(1001), meters(1000))); + static_assert([](auto v) { + auto vv = ++v; + return std::make_pair(v, vv); + }(kilometer) == std::make_pair(meters(1001), meters(1001))); + static_assert([](auto v) { + auto vv = v--; + return std::make_pair(v, vv); + }(kilometer) == std::make_pair(meters(999), meters(1000))); + static_assert([](auto v) { + auto vv = --v; + return std::make_pair(v, vv); + }(kilometer) == std::make_pair(meters(999), meters(999))); + + // compound assignment + + static_assert((1_m += 1_m).count() == 2); + static_assert((2_m -= 1_m).count() == 1); + static_assert((1_m *= 2).count() == 2); + static_assert((2_m /= 2).count() == 1); + static_assert((7_m %= 2).count() == 1); + static_assert((7_m %= 2_m).count() == 1); + + // non-member arithmetic operators + + static_assert(std::is_same_v() + meters()), meters>); + static_assert(std::is_same_v() - meters()), meters>); + static_assert(std::is_same_v() * 1.0f), meters>); + static_assert(std::is_same_v()), meters>); + static_assert(std::is_same_v() / 1.0f), meters>); + static_assert(std::is_same_v() / meters()), float>); + static_assert(std::is_same_v() % short(1)), meters>); + static_assert(std::is_same_v() % meters(1)), meters>); + + static_assert((1_m + kilometer).count() == 1001); + static_assert((1_m + 1_km).count() == 1001); + static_assert((kilometer - 1_m).count() == 999); + static_assert((1_km - 1_m).count() == 999); + static_assert((2_m * 2).count() == 4); + static_assert((3 * 3_m).count() == 9); + static_assert((4_m / 2).count() == 2); + static_assert(4_m / 2_m == 2); + static_assert(4_km / 2000_m == 2); + static_assert((7_m % 2).count() == 1); + static_assert((7_m % 2_m).count() == 1); + static_assert((7_km % 2000_m).count() == 1000); + + // comparators + + static_assert(2_m + 1_m == 3_m); + static_assert(!(2_m + 2_m == 3_m)); + static_assert(2_m + 2_m != 3_m); + static_assert(!(2_m + 2_m != 4_m)); + static_assert(2_m > 1_m); + static_assert(!(1_m > 1_m)); + static_assert(1_m < 2_m); + static_assert(!(2_m < 2_m)); + static_assert(2_m >= 1_m); + static_assert(2_m >= 2_m); + static_assert(!(2_m >= 3_m)); + static_assert(1_m <= 2_m); + static_assert(2_m <= 2_m); + static_assert(!(3_m <= 2_m)); + + static_assert(3_m == 3.0_m); + static_assert(3_m != 3.14_m); + static_assert(2_m > 1.0_m); + static_assert(1.0_m < 2_m); + static_assert(2.0_m >= 1_m); + static_assert(1_m <= 2.0_m); + + static_assert(1000_m == 1_km); + static_assert(1001_m != 1_km); + static_assert(1001_m > 1_km); + static_assert(999_m < 1_km); + static_assert(1000_m >= 1_km); + static_assert(1000_m <= 1_km); // is_quantity -static_assert(units::detail::is_quantity>::value); + static_assert(units::detail::is_quantity>::value); + // common_type -// common_type + static_assert(std::is_same_v, kilometers>, meters>); + static_assert(std::is_same_v, meters>, meters>); + static_assert(std::is_same_v, millimeters>, millimeters>); -static_assert(std::is_same_v, kilometers>, meters>); + // quantity_cast + // static_assert(quantity_cast(2_km).count() == 2000); // should not compile + static_assert(quantity_cast>(2_km).count() == 2000); + static_assert(quantity_cast>(2000_m).count() == 2); -// constructors + // time -constexpr quantity kilometer{1000}; -static_assert(kilometer.count() == 1000); -static_assert(length(kilometer).count() == kilometer.count()); -static_assert(meters(kilometer).count() == kilometer.count()); -static_assert(millimeters(kilometer).count() == kilometer.count() * 1000); -static_assert(quantity_cast>(kilometer).count() == kilometer.count() / 1000); + // static_assert(1_s == 1_m); // should not compile + static_assert(1_h == 3600_s); -//static_assert(meters(1.0) == 1_m); // should not compile -static_assert(meters(1) == 1_m); -static_assert(meters(1.0) == 1_m); -static_assert(meters(1) == 1_m); + // length -//static_assert(kilometers(1000_m) == 1000_m); // should not compile -static_assert(kilometers(1000_m) == 1000_m); -//static_assert(meters(meters(1)) == 1_m); // should not compile -static_assert(meters(quantity_cast>(meters(1))) == 1_m); + static_assert(1_km == 1000_m); + static_assert(1_km + 1_m == 1001_m); + static_assert(10_km / 5_km == 2); + static_assert(10_km / 2 == 5_km); + // velocity -// zero(), min(), max() + static_assert(10_m / 5_s == 2_mps); + static_assert(10 / 5_s * 1_m == 2_mps); + static_assert(1_km / 1_s == 1000_mps); + static_assert(2_kmph * 2_h == 4_km); + static_assert(2_km / 2_kmph == 1_h); -static_assert(length::zero().count() == 0); -static_assert(length::min().count() == std::numeric_limits::min()); -static_assert(length::max().count() == std::numeric_limits::max()); - - -// unary member operators - -static_assert((+1_m).count() == 1); -static_assert((-1_m).count() == -1); - - -// binary member operators - -template> -constexpr auto post_inc(quantity v) -{ - auto vv = v++; - return std::make_pair(v, vv); -} - -template> -constexpr auto pre_inc(quantity v) -{ - auto vv = ++v; - return std::make_pair(v, vv); -} - -template> -constexpr auto post_dec(quantity v) -{ - auto vv = v--; - return std::make_pair(v, vv); -} - -template> -constexpr auto pre_dec(quantity v) -{ - auto vv = --v; - return std::make_pair(v, vv); -} - -constexpr auto r1 = post_inc(1_m); -static_assert(r1.first.count() == 2); -static_assert(r1.second.count() == 1); - -constexpr auto r2 = pre_inc(1_m); -static_assert(r2.first.count() == 2); -static_assert(r2.second.count() == 2); - -constexpr auto r3 = post_dec(1_m); -static_assert(r3.first.count() == 0); -static_assert(r3.second.count() == 1); - -constexpr auto r4 = pre_dec(1_m); -static_assert(r4.first.count() == 0); -static_assert(r4.second.count() == 0); - - -// compound assignment - -static_assert((1_km += 1_km).count() == 2); -static_assert((2_km -= 1_km).count() == 1); -static_assert((1_km *= 2).count() == 2); -static_assert((2_km /= 2).count() == 1); -static_assert((7_km %= 2).count() == 1); -static_assert((7_km %= 2_km).count() == 1); - - -// non-member arithmetic operators - -static_assert((1_km + 1_m).count() == 1001); -static_assert((1_km - 1_m).count() == 999); -static_assert((2_km * 2).count() == 4); -static_assert((3 * 3_km).count() == 9); -static_assert((2_kmph * 2_h).count() == 4); -//static_assert(kilometers(2_kmph * 15_min).count() == 500_m); // should not compile -static_assert(kilometers(2_kmph * 120.0_min).count() == 4); -static_assert(kilometers(2.0_kmph * 120_min).count() == 4); -static_assert((4_km / 2).count() == 2); -static_assert(4_km / 2_km == 2); -static_assert((1_km / 1_s).count() == 1); -//static_assert((1_km / 1_h).count() == 1); // should not compile -static_assert((1.0_km / 1_h).count() == 1); -static_assert((7_km % 2).count() == 1); -static_assert((7_km % 2_km).count() == 1); - - -// comparators - -static_assert(2_km + 1_km == 3_km); -static_assert(!(2_km + 2_km == 3_km)); -static_assert(2_km + 2_km != 3_km); -static_assert(!(2_km + 2_km != 4_km)); -static_assert(2_km > 1_km); -static_assert(!(1_km > 1_km)); -static_assert(1_km < 2_km); -static_assert(!(2_km < 2_km)); -static_assert(2_km >= 1_km); -static_assert(2_km >= 2_km); -static_assert(!(2_km >= 3_km)); -static_assert(1_km <= 2_km); -static_assert(2_km <= 2_km); -static_assert(!(3_km <= 2_km)); - - - -// quantity_cast - -static_assert(quantity_cast>(2000_m) == 2_km); -// static_assert(quantity_cast>(2_m) == 2_s); // should not compile +} // namespace diff --git a/test/test_tools.cpp b/test/test_tools.cpp new file mode 100644 index 00000000..46e3f426 --- /dev/null +++ b/test/test_tools.cpp @@ -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. + +#include "units/si/velocity.h" +#include + +namespace { + + // static_sign + + static_assert(mp::static_sign<2>::value == 1); + static_assert(mp::static_sign<-3>::value == -1); + static_assert(mp::static_sign<0>::value == 1); + + // static_abs + + static_assert(mp::static_abs<2>::value == 2); + static_assert(mp::static_abs<-3>::value == 3); + static_assert(mp::static_abs<0>::value == 0); + + // common_ratio + + static_assert(std::is_same_v, std::kilo>, std::ratio<1>>); + static_assert(std::is_same_v>, std::ratio<1>>); + static_assert(std::is_same_v, std::milli>, std::milli>); + static_assert(std::is_same_v>, std::milli>); + +} // namespace \ No newline at end of file diff --git a/test/test_type_list.cpp b/test/test_type_list.cpp index f2fac0ed..cb14cbc4 100644 --- a/test/test_type_list.cpp +++ b/test/test_type_list.cpp @@ -21,57 +21,100 @@ // SOFTWARE. #include "units/dimension.h" -#include #include -using namespace mp; -using namespace units; +namespace { -// type_list_push_front + using namespace mp; + using namespace units; -static_assert(std::is_same_v, int>, type_list>); -static_assert(std::is_same_v, int, long, double>, type_list>); -static_assert(std::is_same_v, int, long>, type_list>); + // type_list_push_front -// type_list_split_half + static_assert(std::is_same_v, int>, type_list>); + static_assert(std::is_same_v, int, long, double>, type_list>); + static_assert(std::is_same_v, int, long>, type_list>); -static_assert(std::is_same_v>::first_list, type_list>); -static_assert(std::is_same_v>::second_list, type_list<>>); + // type_list_push_back -static_assert(std::is_same_v>::first_list, type_list>); -static_assert(std::is_same_v>::second_list, type_list>); + static_assert(std::is_same_v, int>, type_list>); + static_assert(std::is_same_v, int, long, double>, type_list>); + static_assert(std::is_same_v, int, long>, type_list>); -static_assert(std::is_same_v>::first_list, type_list>); -static_assert(std::is_same_v>::second_list, type_list>); + // type_list_split -static_assert( - std::is_same_v>::first_list, type_list>); -static_assert( - std::is_same_v>::second_list, type_list>); + static_assert(std::is_same_v, 0>::first_list, type_list<>>); + static_assert(std::is_same_v, 0>::second_list, type_list>); -// type_list_merge_sorted + static_assert(std::is_same_v, 1>::first_list, type_list>); + static_assert(std::is_same_v, 1>::second_list, type_list<>>); -static_assert(std::is_same_v>, type_list>, dim_id_less>, - type_list, dim_id<1>>>); -static_assert(std::is_same_v>, type_list>, dim_id_less>, - type_list, dim_id<1>>>); + static_assert(std::is_same_v, 0>::first_list, type_list<>>); + static_assert(std::is_same_v, 0>::second_list, type_list>); -static_assert(std::is_same_v, dim_id<38>>, - type_list, dim_id<43>>, dim_id_less>, - type_list, dim_id<27>, dim_id<38>, dim_id<43>>>); -static_assert( - std::is_same_v, dim_id<82>>, type_list>, dim_id_less>, - type_list, dim_id<10>, dim_id<82>>>); + static_assert(std::is_same_v, 1>::first_list, type_list>); + static_assert(std::is_same_v, 1>::second_list, type_list>); -// type_list_sort + static_assert(std::is_same_v, 2>::first_list, type_list>); + static_assert(std::is_same_v, 2>::second_list, type_list<>>); -static_assert(std::is_same_v>, dim_id_less>, type_list>>); -static_assert( - std::is_same_v, dim_id<1>>, dim_id_less>, type_list, dim_id<1>>>); -static_assert( - std::is_same_v, dim_id<0>>, dim_id_less>, type_list, dim_id<1>>>); -static_assert( - std::is_same_v< - type_list_sort_t, dim_id<27>, dim_id<43>, dim_id<3>, dim_id<9>, dim_id<82>, dim_id<10>>, - dim_id_less>, - type_list, dim_id<9>, dim_id<10>, dim_id<27>, dim_id<38>, dim_id<43>, dim_id<82>>>); + static_assert(std::is_same_v, 1>::first_list, type_list>); + static_assert(std::is_same_v, 1>::second_list, type_list>); + + static_assert(std::is_same_v, 2>::first_list, type_list>); + static_assert(std::is_same_v, 2>::second_list, type_list>); + + // type_list_split_half + + static_assert(std::is_same_v>::first_list, type_list>); + static_assert(std::is_same_v>::second_list, type_list<>>); + + static_assert(std::is_same_v>::first_list, type_list>); + static_assert(std::is_same_v>::second_list, type_list>); + + static_assert(std::is_same_v>::first_list, type_list>); + static_assert(std::is_same_v>::second_list, type_list>); + + static_assert( + std::is_same_v>::first_list, type_list>); + static_assert( + std::is_same_v>::second_list, type_list>); + + // type_list_merge_sorted + + static_assert(std::is_same_v>, type_list>, dim_id_less>, + type_list, dim_id<1>>>); + static_assert(std::is_same_v>, type_list>, dim_id_less>, + type_list, dim_id<1>>>); + + static_assert(std::is_same_v, dim_id<38>>, + type_list, dim_id<43>>, dim_id_less>, + type_list, dim_id<27>, dim_id<38>, dim_id<43>>>); + static_assert( + std::is_same_v, dim_id<82>>, type_list>, dim_id_less>, + type_list, dim_id<10>, dim_id<82>>>); + + // type_list_sort + + template + using dim_sort_t = type_list_sort_t; + + static_assert(std::is_same_v>>, type_list>>); + static_assert(std::is_same_v, dim_id<1>>>, type_list, dim_id<1>>>); + static_assert(std::is_same_v, dim_id<0>>>, type_list, dim_id<1>>>); + static_assert(std::is_same_v< + dim_sort_t, dim_id<27>, dim_id<43>, dim_id<3>, dim_id<9>, dim_id<82>, dim_id<10>>>, + type_list, dim_id<9>, dim_id<10>, dim_id<27>, dim_id<38>, dim_id<43>, dim_id<82>>>); + + // exp_less + + template + using e = exp, Value>; + + template + using exp_sort_t = type_list_sort_t; + + static_assert(std::is_same_v>>, dimension>>); + static_assert(std::is_same_v, e<1, -1>>>, dimension, e<1, -1>>>); + static_assert(std::is_same_v, e<0, -1>>>, dimension, e<1, 1>>>); + +} // namespace diff --git a/test/test_units.cpp b/test/test_units.cpp index 27a44284..6b7c67f7 100644 --- a/test/test_units.cpp +++ b/test/test_units.cpp @@ -20,51 +20,51 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include "units/si/frequency.h" #include "units/si/length.h" #include "units/si/time.h" -#include "units/si/frequency.h" #include "units/si/velocity.h" -#include #include -using namespace units; -using namespace units::literals; +namespace { + using namespace units; + using namespace units::literals; + // frequency -// frequency + static_assert(2 / 1_s == 2_Hz); + static_assert(1000 / 1_s == 1_kHz); + static_assert(3.2_GHz == 3'200'000'000_Hz); -static_assert(2 / 1_s == 2_Hz); -static_assert(1000 / 1_s == 1_kHz); -static_assert(3.2_GHz == 3'200'000'000_Hz); + // time + static_assert(1_h == 3600_s); -// time + // length -static_assert(1_h == 3600_s); + static_assert(1_km == 1000_m); + static_assert(1_km + 1_m == 1001_m); + static_assert(10_km / 5_km == 2); + static_assert(10_km / 2 == 5_km); + // velocity -// length + static_assert(std::is_same_v>>); -static_assert(1_km == 1000_m); -static_assert(10_km / 5_km == 2); -static_assert(10_km / 2 == 5_km); + static_assert(10_m / 5_s == 2_mps); + static_assert(10 / 5_s * 1_m == 2_mps); + static_assert(1_km / 1_s == 1000_mps); + // static_assert(1_km / 1_h == 1_kmph); // should not compile + static_assert(1.0_km / 1_h == 1_kmph); + static_assert(1000.0_m / 3600.0_s == 1_kmph); + static_assert(2_kmph * 2_h == 4_km); + // static_assert(2_kmph * 15_min == 500_m); // should not compile + static_assert(2_kmph * 15.0_min == 500_m); + static_assert(2.0_kmph * 15_min == 500_m); -// velocity + static_assert(2_km / 2_kmph == 1_h); + // static_assert(2000_m / 2_kmph == 1_h); // should not compile + static_assert(quantity_cast>(2000_m) / 2_kmph == 1_h); -static_assert(std::is_same_v>>); - -static_assert(10_m / 5_s == 2_mps); -static_assert(1_km / 1_s == 1000_mps); -//static_assert(1_km / 1_h == 1_kmph); // should not compile -static_assert(1.0_km / 1_h == 1_kmph); -static_assert(1000.0_m / 3600.0_s == 1_kmph); - -static_assert(2_kmph * 2_h == 4_km); -//static_assert(2_kmph * 15_min == 500_m); // should not compile -static_assert(2_kmph * 15.0_min == 500_m); -static_assert(2.0_kmph * 15_min == 500_m); - -static_assert(2_km / 2_kmph == 1_h); -// static_assert(2000_m / 2_kmph == 1_h); // should not compile -static_assert(quantity_cast>(2000_m) / 2_kmph == 1_h); +} // namespace