commit 4b376e3c2e8186f6575c7c74239b16e6a7984beb Author: Mateusz Pusz Date: Wed Aug 22 12:11:19 2018 +0200 Initial version diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..a3461cdf --- /dev/null +++ b/.clang-format @@ -0,0 +1,100 @@ +--- +BasedOnStyle: Google +--- +Language: Cpp +AccessModifierOffset: -2 +# AlignAfterOpenBracket: Align +# AlignConsecutiveAssignments: false +# AlignConsecutiveDeclarations: false +# AlignEscapedNewlinesLeft: true +# AlignOperands: true +# AlignTrailingComments: true +# AllowAllParametersOfDeclarationOnNextLine: true +# AllowShortBlocksOnASingleLine: false +# AllowShortCaseLabelsOnASingleLine: false +# AllowShortFunctionsOnASingleLine: All +# AllowShortIfStatementsOnASingleLine: true +# AllowShortLoopsOnASingleLine: true +# AlwaysBreakAfterDefinitionReturnType: None +# AlwaysBreakAfterReturnType: None +# AlwaysBreakBeforeMultilineStrings: true +# AlwaysBreakTemplateDeclarations: true +# BinPackArguments: true +# BinPackParameters: true +# BraceWrapping: +# AfterClass: false +# AfterControlStatement: false +# AfterEnum: false +# AfterFunction: false +# AfterNamespace: false +# AfterObjCDeclaration: false +# AfterStruct: false +# AfterUnion: false +# BeforeCatch: false +# BeforeElse: false +# IndentBraces: false +# BreakBeforeBinaryOperators: None +BreakBeforeBraces: Stroustrup +# BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true +# BreakAfterJavaFieldAnnotations: false +# BreakStringLiterals: true +ColumnLimit: 120 +# CommentPragmas: '^ IWYU pragma:' +# ConstructorInitializerAllOnOneLineOrOnePerLine: true +# ConstructorInitializerIndentWidth: 4 +# ContinuationIndentWidth: 4 +# Cpp11BracedListStyle: true +DerivePointerAlignment: false +# DisableFormat: false +# ExperimentalAutoDetectBinPacking: false +# ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^".*' + Priority: 1 + - Regex: '^".+/.*' + Priority: 2 + - Regex: '^<.+/.*' + Priority: 3 + - Regex: '^<.*\.h>' + Priority: 4 + - Regex: '^<.*' + Priority: 5 +# IncludeIsMainRegex: '([-_](test|unittest))?$' +# IndentCaseLabels: true +# IndentWidth: 2 +# IndentWrappedFunctionNames: false +# JavaScriptQuotes: Leave +# JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +# MacroBlockBegin: '' +# MacroBlockEnd: '' +# MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +# ObjCBlockIndentWidth: 2 +# ObjCSpaceAfterProperty: false +# ObjCSpaceBeforeProtocolList: false +# PenaltyBreakBeforeFirstCallParameter: 1 +# PenaltyBreakComment: 300 +# PenaltyBreakFirstLessLess: 120 +# PenaltyBreakString: 1000 +# PenaltyExcessCharacter: 1000000 +# PenaltyReturnTypeOnItsOwnLine: 200 +# PointerAlignment: Left +# ReflowComments: true +# SortIncludes: true +# SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +# SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +# SpaceInEmptyParentheses: false +# SpacesBeforeTrailingComments: 2 +# SpacesInAngles: false +# SpacesInContainerLiterals: true +# SpacesInCStyleCastParentheses: false +# SpacesInParentheses: false +# SpacesInSquareBrackets: false +Standard: Cpp11 +# TabWidth: 8 +# UseTab: Never +... diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c35a4df1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# IDE-specific +.*/ +cmake-build-*/ + +# Conan +*.pyc diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..0804a43a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cmake/common"] + path = cmake/common + url = https://github.com/mpusz/cmake_scripts.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..5dd89d06 --- /dev/null +++ b/CMakeLists.txt @@ -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. + +cmake_minimum_required(VERSION 3.8) +project(units) + +# set path to custom cmake modules +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/cmake") + +# include common tools and workarounds +include(tools) + +# use Conan configuration if available +conan_init(cmake_paths) + +# project-specific compilation flags +include(compile_flags) + +# add project code +add_subdirectory(src) + +# add unit tests +enable_testing() +add_subdirectory(test) + +# add usage example +add_subdirectory(example) diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..068aaab3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +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. diff --git a/README.md b/README.md new file mode 100644 index 00000000..75c58b54 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# `units` + +Physical Units library implementation for C++. It bases on std::chrono::duration and adds other +dimensions. diff --git a/cmake/common b/cmake/common new file mode 160000 index 00000000..3cc8c434 --- /dev/null +++ b/cmake/common @@ -0,0 +1 @@ +Subproject commit 3cc8c434b65afdf7b21f693ca20a3a83e363bd86 diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 00000000..baa8d27b --- /dev/null +++ b/conanfile.py @@ -0,0 +1,24 @@ +from conans import ConanFile, CMake + +class UnitConan(ConanFile): + name = "units" + version = "0.0.1" + 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++" + 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) + cmake.configure(source_dir="%s/src" % self.source_folder) + cmake.build() + # cmake.install() + + def package_info(self): + self.cpp_info.libs = ["units"] diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 00000000..e9e89cd8 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,42 @@ +# 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. + +cmake_minimum_required(VERSION 3.8) +project(units_example) + +# set path to custom cmake modules +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake/common/cmake") + +# include common tools and workarounds +include(tools) + +# add dependencies +if(NOT TARGET mp::units) + find_package(units CONFIG REQUIRED) +endif() + +# example app +add_executable(example example.cpp) +target_link_libraries(example + PRIVATE + mp::units +) diff --git a/example/example.cpp b/example/example.cpp new file mode 100644 index 00000000..4f1e2e5e --- /dev/null +++ b/example/example.cpp @@ -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. + +#include "units/si/velocity.h" +#include + + +void foo() +{ + using namespace units; + using namespace units::literals; + + const auto speed = 60_kmph; + const auto time = 10.0_min; + const auto distance = speed * time; + + std::cout << "A car driving " << speed.count() << " km/h in a time of " << time.count() << " minutes will pass " + << quantity_cast>(distance).count() << " meters.\n"; +} + +int main() +{ + try { + foo(); + } + catch (const std::exception& ex) { + std::cerr << "Unhandled std exception caught: " << ex.what() << '\n'; + } + catch (...) { + std::cerr << "Unhandled unknown exception caught\n"; + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..209d56af --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,72 @@ +# 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. + +cmake_minimum_required(VERSION 3.8) +project(units + VERSION 0.0.1 + LANGUAGES C CXX +) + +# set path to custom cmake modules +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/common/cmake") + +# include common tools and workarounds +include(tools) + +# add dependencies +# find_package(...) + +# library definition +add_library(units INTERFACE) +#target_sources(units INTERFACE +# include/units/units.h +# include/units/length.h +# include/units/time.h +# +# include/units/bits/common_type.h +# include/units/bits/dimensions.h +# include/units/bits/quantity.h +# include/units/bits/tools.h +#) +target_compile_features(units INTERFACE cxx_std_17) +target_include_directories(units + INTERFACE + $ + $ + $ +) +add_library(mp::units ALIAS units) + +# installation info +install(TARGETS units EXPORT ${CMAKE_PROJECT_NAME}Targets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin + INCLUDES DESTINATION include +) +install(DIRECTORY include/units + DESTINATION include + COMPONENT Devel +) + +# generate configuration files and install the package +configure_and_install(../cmake/common/cmake/simple_package-config.cmake.in SameMajorVersion) diff --git a/src/include/units/bits/tools.h b/src/include/units/bits/tools.h new file mode 100644 index 00000000..e4c4cd3b --- /dev/null +++ b/src/include/units/bits/tools.h @@ -0,0 +1,84 @@ +// 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 { + + // Requires + + template + using Requires = std::enable_if_t; + + // static_sign + + template + struct static_sign : std::integral_constant { + }; + + // static_abs + + template + struct static_abs : std::integral_constant::value> { + }; + + // static_gcd + + template + struct static_gcd : static_gcd { + }; + + template + struct static_gcd : std::integral_constant::value> { + }; + + template + struct static_gcd<0, Qn> : std::integral_constant::value> { + }; + + // is_ratio + + template + struct is_ratio : std::false_type { + }; + + template + struct is_ratio> : std::true_type { + }; + + // common_ratio + + // todo: simplified + template + struct common_ratio { + using gcd_num = static_gcd; + using gcd_den = static_gcd; + using type = std::ratio; + }; + + 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 new file mode 100644 index 00000000..90c39081 --- /dev/null +++ b/src/include/units/bits/type_list.h @@ -0,0 +1,160 @@ +// 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 "tools.h" +#include + +namespace mp { + + // type_list + + template + struct type_list; + + // push_front + + template + struct type_list_push_front; + + template + struct type_list_push_front, NewTypes...> { + using type = type_list; + }; + + template + using type_list_push_front_t = typename type_list_push_front::type; + + // push_back + + template + struct type_list_push_back; + + template + struct type_list_push_back, NewTypes...> { + using type = type_list; + }; + + template + using type_list_push_back_t = typename type_list_push_back::type; + + // split + + namespace detail { + + template + struct split_impl; + + template + struct split_impl { + using first_list = type_list<>; + using second_list = type_list<>; + }; + + template + struct split_impl : split_impl { + 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>; + }; + + } // namespace detail + + template + struct type_list_split; + + template + struct type_list_split, N> { + using split = detail::split_impl<0, N, Types...>; + using first_list = typename split::first_list; + using second_list = typename split::second_list; + }; + + // split_half + + template + struct type_list_split_half; + + template + struct type_list_split_half> : type_list_split, (sizeof...(Types) + 1) / 2> { + }; + + // merge_sorted + + 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> + struct type_list_merge_sorted, type_list<>, Pred> { + using type = type_list; + }; + + template typename Pred> + struct type_list_merge_sorted, type_list, Pred> { + using type = type_list; + }; + + template typename Pred> + struct type_list_merge_sorted, type_list, Pred> { + using type = std::conditional_t< + Pred::value, + type_list_push_front_t, type_list, Pred>, + Lhs1>, + type_list_push_front_t, type_list, Pred>, + Rhs1>>; + }; + + // sort + + template typename Pred> + struct type_list_sort; + + template typename Pred> + struct type_list_sort, Pred> { + using type = type_list<>; + }; + + template typename Pred> + struct type_list_sort, Pred> { + using type = type_list; + }; + + template typename Pred> + struct type_list_sort, Pred> { + using types = type_list; + using split = type_list_split_half>; + using left = typename type_list_sort::type; + using right = typename type_list_sort::type; + using type = type_list_merge_sorted_t; + }; + + 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 new file mode 100644 index 00000000..e5c5dbba --- /dev/null +++ b/src/include/units/dimension.h @@ -0,0 +1,149 @@ +// 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 "bits/tools.h" +#include "bits/type_list.h" + +namespace units { + + // dim_id + + template + using dim_id = std::integral_constant; + + // dim_id_less + + template + struct dim_id_less : std::bool_constant { + }; + + // exp + + template + struct exp { + using dimension = BaseDimension; + static constexpr int value = Value; + }; + + // exp_less + + template + struct exp_less : dim_id_less { + }; + + // exp_invert + + template + struct exp_invert; + + template + struct exp_invert> { + using type = exp; + }; + + template + using exp_invert_t = typename exp_invert::type; + + // dimension + + template + using dimension = mp::type_list; + + // make_dimension + + namespace detail { + + struct scalar; + + template + struct dim_consolidate; + + template + using dim_consolidate_t = typename dim_consolidate::type; + + 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, 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 + struct make_dimension { + using type = detail::dim_consolidate_t, exp_less>>; + }; + + template + using make_dimension_t = typename make_dimension::type; + + // dimension_multiply + + template + struct dimension_multiply; + + template + struct dimension_multiply, dimension> { + using type = make_dimension_t; + }; + + template + using dimension_multiply_t = typename dimension_multiply::type; + + // dimension_divide + + template + struct dimension_divide; + + template + struct dimension_divide, dimension> + : dimension_multiply, dimension...>> { + }; + + 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 new file mode 100644 index 00000000..54480c24 --- /dev/null +++ b/src/include/units/quantity.h @@ -0,0 +1,368 @@ +// 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 "bits/tools.h" +#include "dimension.h" +#include + +namespace units { + + template + class quantity; + + // is_quantity + + namespace detail { + + template + struct is_quantity : std::false_type { + }; + + template + struct is_quantity> : std::true_type { + }; + + } + + // treat_as_floating_point + + template + struct treat_as_floating_point : std::is_floating_point {}; + + template + inline constexpr bool treat_as_floating_point_v = treat_as_floating_point::value; + + // quantity_cast + + namespace detail { + + template + struct quantity_cast_impl { + template + static constexpr To cast(const quantity& q) + { + return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num) / + static_cast(CRatio::den))); + } + }; + + template + struct quantity_cast_impl { + template + static constexpr To cast(const quantity& q) + { + return To(static_cast(q.count())); + } + }; + + template + struct quantity_cast_impl { + template + static constexpr To cast(const quantity& q) + { + return To(static_cast(static_cast(q.count()) / static_cast(CRatio::den))); + } + }; + + template + struct quantity_cast_impl { + template + static constexpr To cast(const quantity& q) + { + return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num))); + } + }; + + } // namespace detail + + template::value && std::is_same_v> = true> + constexpr To quantity_cast(const quantity& q) + { + using c_ratio = std::ratio_divide; + using c_rep = std::common_type_t; + using cast = detail::quantity_cast_impl; + return cast::cast(q); + } + + // quantity_values + + template + struct quantity_values { + static constexpr Rep zero() { return Rep(0); } + static constexpr Rep max() { return std::numeric_limits::max(); } + static constexpr Rep min() { return std::numeric_limits::lowest(); } + }; + + // quantity + + template> + class quantity { + Rep value_; + public: + using dimension = Dimension; + using rep = Rep; + 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> + constexpr explicit quantity(const Rep2& r) : value_{static_cast(r)} + { + } + + template || + (std::ratio_divide::den == 1 && !treat_as_floating_point::value)> = true> + constexpr quantity(const quantity& q) : value_{quantity_cast(q).count()} + { + } + + quantity& operator=(const quantity& other) = default; + + constexpr rep count() const noexcept { return value_; } + + static constexpr quantity zero() { return quantity(quantity_values::zero()); } + static constexpr quantity min() { return quantity(quantity_values::min()); } + static constexpr quantity max() { return quantity(quantity_values::max()); } + + constexpr std::common_type_t operator+() const { return quantity(*this); } + constexpr std::common_type_t operator-() const { return quantity(-count()); } + + constexpr quantity& operator++() + { + ++value_; + return *this; + } + constexpr quantity operator++(int) { return quantity(value_++); } + + constexpr quantity& operator--() + { + --value_; + return *this; + } + constexpr quantity operator--(int) { return quantity(value_--); } + + constexpr quantity& operator+=(const quantity& q) + { + value_ += q.count(); + return *this; + } + + constexpr quantity& operator-=(const quantity& q) + { + value_ -= q.count(); + return *this; + } + + constexpr quantity& operator*=(const rep& rhs) + { + value_ *= rhs; + return *this; + } + + constexpr quantity& operator/=(const rep& rhs) + { + value_ /= rhs; + return *this; + } + + constexpr quantity& operator%=(const rep& rhs) + { + value_ %= rhs; + return *this; + } + + constexpr quantity& operator%=(const quantity& q) + { + value_ %= q.count(); + return *this; + } + }; + + // clang-format off + template + std::common_type_t, quantity> + constexpr operator+(const quantity& lhs, + const quantity& rhs) + { + using ret = std::common_type_t, quantity>; + return ret(ret(lhs).count() + ret(rhs).count()); + } + + template + std::common_type_t, quantity> + constexpr operator-(const quantity& lhs, + const quantity& rhs) + { + using ret = std::common_type_t, quantity>; + return ret(ret(lhs).count() - ret(rhs).count()); + } + + template + quantity, Ratio> + constexpr operator*(const quantity& q, + const Rep2& v) + { + using ret = quantity, Ratio>; + return ret(ret(q).count() * v); + } + + template + quantity, Ratio> + constexpr operator*(const Rep1& v, + const quantity& q) + { + return q * v; + } + + template> || std::ratio_multiply::den == 1> = true> + quantity, std::common_type_t, std::ratio_multiply> + constexpr operator*(const quantity& lhs, + const quantity& rhs) + { + using ret = quantity, std::common_type_t, std::ratio_multiply>; + return ret(lhs.count() * rhs.count()); + } + + template + quantity>, std::common_type_t, Ratio> + constexpr operator/(const Rep1& v, + const quantity, Rep2, Ratio>& q) + { + using ret = quantity>, std::common_type_t, Ratio>; + using den = quantity, std::common_type_t, Ratio>; + return ret(v / den(q).count()); + } + + template + quantity, Ratio> + constexpr operator/(const quantity& q, + const Rep2& v) + { + using ret = quantity, Ratio>; + return ret(ret(q).count() / v); + } + + template + std::common_type_t + constexpr operator/(const quantity& lhs, + const quantity& rhs) + { + using cq = std::common_type_t, quantity>; + return cq(lhs).count() / cq(rhs).count(); + } + + template> || std::ratio_divide::den == 1> = true> + quantity, std::common_type_t, std::ratio_divide> + constexpr operator/(const quantity& lhs, + const quantity& rhs) + { + using ret = quantity, std::common_type_t, std::ratio_divide>; + return ret(lhs.count() / rhs.count()); + } + + template + quantity, Ratio> + constexpr operator%(const quantity& q, + const Rep2& v) + { + using ret = quantity, Ratio>; + return ret(ret(q).count() % v); + } + + template + std::common_type_t, quantity> + constexpr operator%(const quantity& lhs, + const quantity& rhs) + { + using ret = std::common_type_t, quantity>; + return ret(ret(lhs).count() % ret(rhs).count()); + } + + template + constexpr bool operator==(const quantity& lhs, + const quantity& rhs) + { + using ct = std::common_type_t, quantity>; + return ct(lhs).count() == ct(rhs).count(); + } + + template + constexpr bool operator!=(const quantity& lhs, + const quantity& rhs) + { + return !(lhs == rhs); + } + + template + constexpr bool operator<(const quantity& lhs, + const quantity& rhs) + { + using ct = std::common_type_t, quantity>; + return ct(lhs).count() < ct(rhs).count(); + } + + template + constexpr bool operator<=(const quantity& lhs, + const quantity& rhs) + { + return !(rhs < lhs); + } + + template + constexpr bool operator>(const quantity& lhs, + const quantity& rhs) + { + return rhs < lhs; + } + + template + constexpr bool operator>=(const quantity& lhs, + const quantity& rhs) + { + return !(lhs < rhs); + } + // clang-format on + +} // namespace units + +namespace std { + + // todo: simplified + template + struct common_type, units::quantity> { + using type = + units::quantity, mp::common_ratio_t>; + }; + +} // namespace std diff --git a/src/include/units/si/base_dimensions.h b/src/include/units/si/base_dimensions.h new file mode 100644 index 00000000..2a95d98d --- /dev/null +++ b/src/include/units/si/base_dimensions.h @@ -0,0 +1,38 @@ +// 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 "../dimension.h" +#include "../quantity.h" + +namespace units { + + 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> {}; + +} // namespace units diff --git a/src/include/units/si/frequency.h b/src/include/units/si/frequency.h new file mode 100644 index 00000000..0d9bb42b --- /dev/null +++ b/src/include/units/si/frequency.h @@ -0,0 +1,83 @@ +// 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 "base_dimensions.h" +#include "time.h" + +namespace units { + + using dimension_frequency = make_dimension_t>; + + template> + using frequency = quantity; + + template + using millihertzs = frequency; + + template + using hertzs = frequency; + + template + using kilohertzs = frequency; + + template + using megahertzs = frequency; + + template + using gigahertzs = frequency; + + template + using terahertzs = frequency; + + // ... + + namespace literals { + + // mHz + constexpr auto operator""_mHz(unsigned long long l) { return millihertzs(l); } + constexpr auto operator""_mHz(long double l) { return millihertzs(l); } + + // Hz + constexpr auto operator""_Hz(unsigned long long l) { return hertzs(l); } + constexpr auto operator""_Hz(long double l) { return hertzs(l); } + + // kHz + constexpr auto operator""_kHz(unsigned long long l) { return kilohertzs(l); } + constexpr auto operator""_kHz(long double l) { return kilohertzs(l); } + + // MHz + constexpr auto operator""_MHz(unsigned long long l) { return megahertzs(l); } + constexpr auto operator""_MHz(long double l) { return megahertzs(l); } + + // GHz + constexpr auto operator""_GHz(unsigned long long l) { return gigahertzs(l); } + constexpr auto operator""_GHz(long double l) { return gigahertzs(l); } + + // THz + constexpr auto operator""_THz(unsigned long long l) { return terahertzs(l); } + constexpr auto operator""_THz(long double l) { return terahertzs(l); } + + } // namespace literals + +} // namespace units diff --git a/src/include/units/si/length.h b/src/include/units/si/length.h new file mode 100644 index 00000000..29e40049 --- /dev/null +++ b/src/include/units/si/length.h @@ -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 "base_dimensions.h" + +namespace units { + + using dimension_length = make_dimension_t>; + + template> + using length = quantity; + + template + using millimeters = length; + + template + using meters = length; + + template + using kilometers = length; + + // ... + + namespace literals { + + // mm + constexpr auto operator""_mm(unsigned long long l) { return millimeters(l); } + constexpr auto operator""_mm(long double l) { return millimeters(l); } + + // m + constexpr auto operator""_m(unsigned long long l) { return meters(l); } + constexpr auto operator""_m(long double l) { return meters(l); } + + // km + constexpr auto operator""_km(unsigned long long l) { return kilometers(l); } + constexpr auto operator""_km(long double l) { return kilometers(l); } + + } // namespace literals + +} // namespace units diff --git a/src/include/units/si/time.h b/src/include/units/si/time.h new file mode 100644 index 00000000..db01847a --- /dev/null +++ b/src/include/units/si/time.h @@ -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 "base_dimensions.h" + +namespace units { + + using dimension_time = make_dimension_t>; + + template> + using time = quantity; + + template + using nanoseconds = time; + + template + using microseconds = time; + + template + using milliseconds = time; + + template + using seconds = time; + + template + using minutes = time>; + + template + using hours = time>; + + // ... + + namespace literals { + + // ns + constexpr auto operator""_ns(unsigned long long l) { return nanoseconds(l); } + constexpr auto operator""_ns(long double l) { return nanoseconds(l); } + + // us + constexpr auto operator""_us(unsigned long long l) { return microseconds(l); } + constexpr auto operator""_us(long double l) { return microseconds(l); } + + // ms + constexpr auto operator""_ms(unsigned long long l) { return milliseconds(l); } + constexpr auto operator""_ms(long double l) { return milliseconds(l); } + + // s + constexpr auto operator""_s(unsigned long long l) { return seconds(l); } + constexpr auto operator""_s(long double l) { return seconds(l); } + + // min + constexpr auto operator""_min(unsigned long long l) { return minutes(l); } + constexpr auto operator""_min(long double l) { return minutes(l); } + + // h + constexpr auto operator""_h(unsigned long long l) { return hours(l); } + constexpr auto operator""_h(long double l) { return hours(l); } + + } // namespace literals + +} // namespace units diff --git a/src/include/units/si/velocity.h b/src/include/units/si/velocity.h new file mode 100644 index 00000000..069c803a --- /dev/null +++ b/src/include/units/si/velocity.h @@ -0,0 +1,63 @@ +// 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 "base_dimensions.h" +#include "length.h" +#include "time.h" + +namespace units { + + using dimension_velocity = make_dimension_t, exp>; + + template> + using velocity = quantity; + + template + using meters_per_second = velocity; + + template + using kilometers_per_hour = velocity>; + + template + using miles_per_hour = velocity>; + + // ... + + namespace literals { + + // mps + constexpr auto operator""_mps(unsigned long long l) { return meters_per_second(l); } + constexpr auto operator""_mps(long double l) { return meters_per_second(l); } + + // kmph + constexpr auto operator""_kmph(unsigned long long l) { return kilometers_per_hour(l); } + constexpr auto operator""_kmph(long double l) { return kilometers_per_hour(l); } + + // mph + constexpr auto operator""_mph(unsigned long long l) { return miles_per_hour(l); } + constexpr auto operator""_mph(long double l) { return miles_per_hour(l); } + + } // namespace literals + +} // namespace units diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 00000000..4220865d --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,54 @@ +# 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. + +cmake_minimum_required(VERSION 3.8) +project(units_test) + +# set path to custom cmake modules +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake/common/cmake") + +# include common tools and workarounds +include(tools) + +# add dependencies +enable_testing() +find_package(GTest MODULE REQUIRED) +if(NOT TARGET mp::units) + find_package(units CONFIG REQUIRED) +endif() + +# unit tests +add_executable(unit_tests + test_dimension.cpp + test_quantity.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 + unit_tests +) diff --git a/test/test_dimension.cpp b/test/test_dimension.cpp new file mode 100644 index 00000000..8607d264 --- /dev/null +++ b/test/test_dimension.cpp @@ -0,0 +1,65 @@ +// 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/dimension.h" +#include +#include + +using namespace units; + +namespace { + + template + using e = exp, Value>; +} + +// make_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>); + +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, 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_multiply + +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>); diff --git a/test/test_quantity.cpp b/test/test_quantity.cpp new file mode 100644 index 00000000..d4154d69 --- /dev/null +++ b/test/test_quantity.cpp @@ -0,0 +1,173 @@ +// 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 +#include + +using namespace units; +using namespace units::literals; + + + +// is_quantity + +static_assert(units::detail::is_quantity>::value); + + +// common_type + +static_assert(std::is_same_v, kilometers>, meters>); + + +// constructors + +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(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); + +//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); + + +// zero(), min(), max() + +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 diff --git a/test/test_type_list.cpp b/test/test_type_list.cpp new file mode 100644 index 00000000..f2fac0ed --- /dev/null +++ b/test/test_type_list.cpp @@ -0,0 +1,77 @@ +// 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/dimension.h" +#include +#include + +using namespace mp; +using namespace units; + +// type_list_push_front + +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_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 + +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>>>); diff --git a/test/test_units.cpp b/test/test_units.cpp new file mode 100644 index 00000000..27a44284 --- /dev/null +++ b/test/test_units.cpp @@ -0,0 +1,70 @@ +// 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/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; + + +// 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); + + +// time + +static_assert(1_h == 3600_s); + + +// length + +static_assert(1_km == 1000_m); +static_assert(10_km / 5_km == 2); +static_assert(10_km / 2 == 5_km); + + +// velocity + +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);