Initial version

This commit is contained in:
Mateusz Pusz
2018-08-22 12:11:19 +02:00
commit 4b376e3c2e
25 changed files with 1927 additions and 0 deletions

100
.clang-format Normal file
View File

@ -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
...

36
.gitignore vendored Normal file
View File

@ -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

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "cmake/common"]
path = cmake/common
url = https://github.com/mpusz/cmake_scripts.git

46
CMakeLists.txt Normal file
View File

@ -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)

21
LICENSE Normal file
View File

@ -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.

4
README.md Normal file
View File

@ -0,0 +1,4 @@
# `units`
Physical Units library implementation for C++. It bases on std::chrono::duration and adds other
dimensions.

1
cmake/common Submodule

Submodule cmake/common added at 3cc8c434b6

24
conanfile.py Normal file
View File

@ -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"]

42
example/CMakeLists.txt Normal file
View File

@ -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
)

51
example/example.cpp Normal file
View File

@ -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 <iostream>
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<meters<int>>(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";
}
}

72
src/CMakeLists.txt Normal file
View File

@ -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
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)
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)

View File

@ -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 <ratio>
#include <type_traits>
namespace mp {
// Requires
template<bool B>
using Requires = std::enable_if_t<B, bool>;
// static_sign
template<std::intmax_t Pn>
struct static_sign : std::integral_constant<std::intmax_t, (Pn < 0) ? -1 : 1> {
};
// static_abs
template<std::intmax_t Pn>
struct static_abs : std::integral_constant<std::intmax_t, Pn * static_sign<Pn>::value> {
};
// static_gcd
template<std::intmax_t Pn, std::intmax_t Qn>
struct static_gcd : static_gcd<Qn, (Pn % Qn)> {
};
template<std::intmax_t Pn>
struct static_gcd<Pn, 0> : std::integral_constant<std::intmax_t, static_abs<Pn>::value> {
};
template<std::intmax_t Qn>
struct static_gcd<0, Qn> : std::integral_constant<std::intmax_t, static_abs<Qn>::value> {
};
// is_ratio
template<typename T>
struct is_ratio : std::false_type {
};
template<intmax_t Num, intmax_t Den>
struct is_ratio<std::ratio<Num, Den>> : std::true_type {
};
// common_ratio
// todo: simplified
template<typename Ratio1, typename Ratio2>
struct common_ratio {
using gcd_num = static_gcd<Ratio1::num, Ratio2::num>;
using gcd_den = static_gcd<Ratio1::den, Ratio2::den>;
using type = std::ratio<gcd_num::value, (Ratio1::den / gcd_den::value) * Ratio2::den>;
};
template<typename Ratio1, typename Ratio2>
using common_ratio_t = typename common_ratio<Ratio1, Ratio2>::type;
} // namespace mp

View File

@ -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 <type_traits>
namespace mp {
// type_list
template<typename... Types>
struct type_list;
// push_front
template<typename TypeList, typename... Types>
struct type_list_push_front;
template<typename... OldTypes, typename... NewTypes>
struct type_list_push_front<type_list<OldTypes...>, NewTypes...> {
using type = type_list<NewTypes..., OldTypes...>;
};
template<typename TypeList, typename... Types>
using type_list_push_front_t = typename type_list_push_front<TypeList, Types...>::type;
// push_back
template<typename TypeList, typename... Types>
struct type_list_push_back;
template<typename... OldTypes, typename... NewTypes>
struct type_list_push_back<type_list<OldTypes...>, NewTypes...> {
using type = type_list<OldTypes..., NewTypes...>;
};
template<typename TypeList, typename... Types>
using type_list_push_back_t = typename type_list_push_back<TypeList, Types...>::type;
// split
namespace detail {
template<std::size_t Idx, std::size_t N, typename... Types>
struct split_impl;
template<std::size_t Idx, std::size_t N>
struct split_impl<Idx, N> {
using first_list = type_list<>;
using second_list = type_list<>;
};
template<std::size_t Idx, std::size_t N, typename T, typename... Rest>
struct split_impl<Idx, N, T, Rest...> : split_impl<Idx + 1, N, Rest...> {
using base = split_impl<Idx + 1, N, Rest...>;
using base_first = typename base::first_list;
using base_second = typename base::second_list;
using first_list = std::conditional_t < Idx<N, type_list_push_front_t<base_first, T>, base_first>;
using second_list = std::conditional_t < Idx<N, base_second, type_list_push_front_t<base_second, T>>;
};
} // namespace detail
template<typename T, std::size_t N>
struct type_list_split;
template<std::size_t N, typename... Types>
struct type_list_split<type_list<Types...>, 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<typename T>
struct type_list_split_half;
template<typename... Types>
struct type_list_split_half<type_list<Types...>> : type_list_split<type_list<Types...>, (sizeof...(Types) + 1) / 2> {
};
// merge_sorted
template<typename T1, typename T2, template<typename, typename> typename Pred>
struct type_list_merge_sorted;
template<typename T1, typename T2, template<typename, typename> typename Pred>
using type_list_merge_sorted_t = typename type_list_merge_sorted<T1, T2, Pred>::type;
template<typename... Lhs, template<typename, typename> typename Pred>
struct type_list_merge_sorted<type_list<Lhs...>, type_list<>, Pred> {
using type = type_list<Lhs...>;
};
template<typename... Rhs, template<typename, typename> typename Pred>
struct type_list_merge_sorted<type_list<>, type_list<Rhs...>, Pred> {
using type = type_list<Rhs...>;
};
template<typename Lhs1, typename... LhsRest, typename Rhs1, typename... RhsRest,
template<typename, typename> typename Pred>
struct type_list_merge_sorted<type_list<Lhs1, LhsRest...>, type_list<Rhs1, RhsRest...>, Pred> {
using type = std::conditional_t<
Pred<Lhs1, Rhs1>::value,
type_list_push_front_t<type_list_merge_sorted_t<type_list<LhsRest...>, type_list<Rhs1, RhsRest...>, Pred>,
Lhs1>,
type_list_push_front_t<type_list_merge_sorted_t<type_list<Lhs1, LhsRest...>, type_list<RhsRest...>, Pred>,
Rhs1>>;
};
// sort
template<typename T, template<typename, typename> typename Pred>
struct type_list_sort;
template<template<typename, typename> typename Pred>
struct type_list_sort<type_list<>, Pred> {
using type = type_list<>;
};
template<typename T, template<typename, typename> typename Pred>
struct type_list_sort<type_list<T>, Pred> {
using type = type_list<T>;
};
template<typename... Types, template<typename, typename> typename Pred>
struct type_list_sort<type_list<Types...>, Pred> {
using types = type_list<Types...>;
using split = type_list_split_half<type_list<Types...>>;
using left = typename type_list_sort<typename split::first_list, Pred>::type;
using right = typename type_list_sort<typename split::second_list, Pred>::type;
using type = type_list_merge_sorted_t<left, right, Pred>;
};
template<typename T, template<typename, typename> typename Pred>
using type_list_sort_t = typename type_list_sort<T, Pred>::type;
} // namespace mp

View File

@ -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<int UniqueValue>
using dim_id = std::integral_constant<int, UniqueValue>;
// dim_id_less
template<typename D1, typename D2>
struct dim_id_less : std::bool_constant<D1::value<D2::value> {
};
// exp
template<typename BaseDimension, int Value>
struct exp {
using dimension = BaseDimension;
static constexpr int value = Value;
};
// exp_less
template<typename E1, typename E2>
struct exp_less : dim_id_less<typename E1::dimension, typename E2::dimension> {
};
// exp_invert
template<typename Exponent>
struct exp_invert;
template<typename BaseDimension, int Value>
struct exp_invert<exp<BaseDimension, Value>> {
using type = exp<BaseDimension, -Value>;
};
template<typename Exponent>
using exp_invert_t = typename exp_invert<Exponent>::type;
// dimension
template<typename... Exponents>
using dimension = mp::type_list<Exponents...>;
// make_dimension
namespace detail {
struct scalar;
template<typename D>
struct dim_consolidate;
template<typename D>
using dim_consolidate_t = typename dim_consolidate<D>::type;
template<>
struct dim_consolidate<dimension<>> {
using type = dimension<scalar>;
};
template<typename E1>
struct dim_consolidate<dimension<E1>> {
using type = dimension<E1>;
};
template<typename... ERest>
struct dim_consolidate<dimension<scalar, ERest...>> {
using type = dim_consolidate_t<dimension<ERest...>>;
};
template<typename D, int V1, int V2, typename... ERest>
struct dim_consolidate<dimension<exp<D, V1>, exp<D, V2>, ERest...>> {
using type = std::conditional_t<V1 + V2 == 0, dim_consolidate_t<dimension<ERest...>>,
dim_consolidate_t<dimension<exp<D, V1 + V2>, ERest...>>>;
};
template<typename E1, typename... ERest>
struct dim_consolidate<dimension<E1, ERest...>> {
using rest = dim_consolidate_t<dimension<ERest...>>;
using type = std::conditional_t<std::is_same_v<rest, dimension<scalar>>, dimension<E1>,
mp::type_list_push_front_t<rest, E1>>;
};
} // namespace detail
template<typename... Exponents>
struct make_dimension {
using type = detail::dim_consolidate_t<mp::type_list_sort_t<mp::type_list<Exponents...>, exp_less>>;
};
template<typename... Exponents>
using make_dimension_t = typename make_dimension<Exponents...>::type;
// dimension_multiply
template<typename D1, typename D2>
struct dimension_multiply;
template<typename... Exp1, typename... Exp2>
struct dimension_multiply<dimension<Exp1...>, dimension<Exp2...>> {
using type = make_dimension_t<Exp1..., Exp2...>;
};
template<typename D1, typename D2>
using dimension_multiply_t = typename dimension_multiply<D1, D2>::type;
// dimension_divide
template<typename D1, typename D2>
struct dimension_divide;
template<typename... Exp1, typename... Exp2>
struct dimension_divide<dimension<Exp1...>, dimension<Exp2...>>
: dimension_multiply<dimension<Exp1...>, dimension<exp_invert_t<Exp2>...>> {
};
template<typename D1, typename D2>
using dimension_divide_t = typename dimension_divide<D1, D2>::type;
} // namespace units

View File

@ -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 <limits>
namespace units {
template<typename Dimension, typename Rep, class Ratio>
class quantity;
// is_quantity
namespace detail {
template<typename T>
struct is_quantity : std::false_type {
};
template<typename Dimension, typename Rep, class Ratio>
struct is_quantity<quantity<Dimension, Rep, Ratio>> : std::true_type {
};
}
// treat_as_floating_point
template<class Rep>
struct treat_as_floating_point : std::is_floating_point<Rep> {};
template<class Rep>
inline constexpr bool treat_as_floating_point_v = treat_as_floating_point<Rep>::value;
// quantity_cast
namespace detail {
template<typename To, typename CRatio, typename CRep, bool NumIsOne = false, bool DenIsOne = false>
struct quantity_cast_impl {
template<typename Dimension, typename Rep, typename Ratio>
static constexpr To cast(const quantity<Dimension, Rep, Ratio>& q)
{
return To(static_cast<typename To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num) /
static_cast<CRep>(CRatio::den)));
}
};
template<typename To, typename CRatio, typename CRep>
struct quantity_cast_impl<To, CRatio, CRep, true, true> {
template<typename Dimension, typename Rep, typename Ratio>
static constexpr To cast(const quantity<Dimension, Rep, Ratio>& q)
{
return To(static_cast<typename To::rep>(q.count()));
}
};
template<typename To, typename CRatio, typename CRep>
struct quantity_cast_impl<To, CRatio, CRep, true, false> {
template<typename Dimension, typename Rep, typename Ratio>
static constexpr To cast(const quantity<Dimension, Rep, Ratio>& q)
{
return To(static_cast<typename To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(CRatio::den)));
}
};
template<typename To, typename CRatio, typename CRep>
struct quantity_cast_impl<To, CRatio, CRep, false, true> {
template<typename Dimension, typename Rep, typename Ratio>
static constexpr To cast(const quantity<Dimension, Rep, Ratio>& q)
{
return To(static_cast<typename To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num)));
}
};
} // namespace detail
template<typename To, typename Dimension, typename Rep, typename Ratio,
mp::Requires<detail::is_quantity<To>::value && std::is_same_v<typename To::dimension, Dimension>> = true>
constexpr To quantity_cast(const quantity<Dimension, Rep, Ratio>& q)
{
using c_ratio = std::ratio_divide<Ratio, typename To::ratio>;
using c_rep = std::common_type_t<typename To::rep, Rep, intmax_t>;
using cast = detail::quantity_cast_impl<To, c_ratio, c_rep, c_ratio::num == 1, c_ratio::den == 1>;
return cast::cast(q);
}
// quantity_values
template<typename Rep>
struct quantity_values {
static constexpr Rep zero() { return Rep(0); }
static constexpr Rep max() { return std::numeric_limits<Rep>::max(); }
static constexpr Rep min() { return std::numeric_limits<Rep>::lowest(); }
};
// quantity
template<typename Dimension, typename Rep, class Ratio = std::ratio<1>>
class quantity {
Rep value_;
public:
using dimension = Dimension;
using rep = Rep;
using ratio = Ratio;
static_assert(!detail::is_quantity<Rep>::value, "rep cannot be a quantity");
static_assert(mp::is_ratio<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<class Rep2, mp::Requires<std::is_convertible_v<Rep2, rep> &&
(treat_as_floating_point_v<rep> || !treat_as_floating_point_v<Rep2>)> = true>
constexpr explicit quantity(const Rep2& r) : value_{static_cast<rep>(r)}
{
}
template<class Rep2, class Ratio2,
mp::Requires<treat_as_floating_point_v<rep> ||
(std::ratio_divide<Ratio2, ratio>::den == 1 && !treat_as_floating_point<Rep2>::value)> = true>
constexpr quantity(const quantity<Dimension, Rep2, Ratio2>& q) : value_{quantity_cast<quantity>(q).count()}
{
}
quantity& operator=(const quantity& other) = default;
constexpr rep count() const noexcept { return value_; }
static constexpr quantity zero() { return quantity(quantity_values<Rep>::zero()); }
static constexpr quantity min() { return quantity(quantity_values<Rep>::min()); }
static constexpr quantity max() { return quantity(quantity_values<Rep>::max()); }
constexpr std::common_type_t<quantity> operator+() const { return quantity(*this); }
constexpr std::common_type_t<quantity> 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<typename Dimension, typename Rep1, class Ratio1, typename Rep2, class Ratio2>
std::common_type_t<quantity<Dimension, Rep1, Ratio1>, quantity<Dimension, Rep2, Ratio2>>
constexpr operator+(const quantity<Dimension, Rep1, Ratio1>& lhs,
const quantity<Dimension, Rep2, Ratio2>& rhs)
{
using ret = std::common_type_t<quantity<Dimension, Rep1, Ratio1>, quantity<Dimension, Rep2, Ratio2>>;
return ret(ret(lhs).count() + ret(rhs).count());
}
template<typename Dimension, typename Rep1, class Ratio1, typename Rep2, class Ratio2>
std::common_type_t<quantity<Dimension, Rep1, Ratio1>, quantity<Dimension, Rep2, Ratio2>>
constexpr operator-(const quantity<Dimension, Rep1, Ratio1>& lhs,
const quantity<Dimension, Rep2, Ratio2>& rhs)
{
using ret = std::common_type_t<quantity<Dimension, Rep1, Ratio1>, quantity<Dimension, Rep2, Ratio2>>;
return ret(ret(lhs).count() - ret(rhs).count());
}
template<typename Dimension, typename Rep1, class Ratio, typename Rep2>
quantity<Dimension, std::common_type_t<Rep1, Rep2>, Ratio>
constexpr operator*(const quantity<Dimension, Rep1, Ratio>& q,
const Rep2& v)
{
using ret = quantity<Dimension, std::common_type_t<Rep1, Rep2>, Ratio>;
return ret(ret(q).count() * v);
}
template<typename Dimension, typename Rep1, typename Rep2, class Ratio>
quantity<Dimension, std::common_type_t<Rep1, Rep2>, Ratio>
constexpr operator*(const Rep1& v,
const quantity<Dimension, Rep2, Ratio>& q)
{
return q * v;
}
template<typename Dimension1, typename Rep1, class Ratio1, typename Dimension2, typename Rep2, class Ratio2,
mp::Requires<treat_as_floating_point_v<std::common_type_t<Rep1, Rep2>> || std::ratio_multiply<Ratio1, Ratio2>::den == 1> = true>
quantity<dimension_multiply_t<Dimension1, Dimension2>, std::common_type_t<Rep1, Rep2>, std::ratio_multiply<Ratio1, Ratio2>>
constexpr operator*(const quantity<Dimension1, Rep1, Ratio1>& lhs,
const quantity<Dimension2, Rep2, Ratio2>& rhs)
{
using ret = quantity<dimension_multiply_t<Dimension1, Dimension2>, std::common_type_t<Rep1, Rep2>, std::ratio_multiply<Ratio1, Ratio2>>;
return ret(lhs.count() * rhs.count());
}
template<typename Rep1, typename Exponent, class Ratio, typename Rep2>
quantity<dimension<exp_invert_t<Exponent>>, std::common_type_t<Rep1, Rep2>, Ratio>
constexpr operator/(const Rep1& v,
const quantity<dimension<Exponent>, Rep2, Ratio>& q)
{
using ret = quantity<dimension<exp_invert_t<Exponent>>, std::common_type_t<Rep1, Rep2>, Ratio>;
using den = quantity<dimension<Exponent>, std::common_type_t<Rep1, Rep2>, Ratio>;
return ret(v / den(q).count());
}
template<typename Dimension, typename Rep1, class Ratio, typename Rep2>
quantity<Dimension, std::common_type_t<Rep1, Rep2>, Ratio>
constexpr operator/(const quantity<Dimension, Rep1, Ratio>& q,
const Rep2& v)
{
using ret = quantity<Dimension, std::common_type_t<Rep1, Rep2>, Ratio>;
return ret(ret(q).count() / v);
}
template<typename Dimension, typename Rep1, class Ratio1, typename Rep2, class Ratio2>
std::common_type_t<Rep1, Rep2>
constexpr operator/(const quantity<Dimension, Rep1, Ratio1>& lhs,
const quantity<Dimension, Rep2, Ratio2>& rhs)
{
using cq = std::common_type_t<quantity<Dimension, Rep1, Ratio1>, quantity<Dimension, Rep2, Ratio2>>;
return cq(lhs).count() / cq(rhs).count();
}
template<typename Dimension1, typename Rep1, class Ratio1, typename Dimension2, typename Rep2, class Ratio2,
mp::Requires<treat_as_floating_point_v<std::common_type_t<Rep1, Rep2>> || std::ratio_divide<Ratio1, Ratio2>::den == 1> = true>
quantity<dimension_divide_t<Dimension1, Dimension2>, std::common_type_t<Rep1, Rep2>, std::ratio_divide<Ratio1, Ratio2>>
constexpr operator/(const quantity<Dimension1, Rep1, Ratio1>& lhs,
const quantity<Dimension2, Rep2, Ratio2>& rhs)
{
using ret = quantity<dimension_divide_t<Dimension1, Dimension2>, std::common_type_t<Rep1, Rep2>, std::ratio_divide<Ratio1, Ratio2>>;
return ret(lhs.count() / rhs.count());
}
template<typename Dimension, typename Rep1, class Ratio, typename Rep2>
quantity<Dimension, std::common_type_t<Rep1, Rep2>, Ratio>
constexpr operator%(const quantity<Dimension, Rep1, Ratio>& q,
const Rep2& v)
{
using ret = quantity<Dimension, std::common_type_t<Rep1, Rep2>, Ratio>;
return ret(ret(q).count() % v);
}
template<typename Dimension, typename Rep1, class Ratio1, typename Rep2, class Ratio2>
std::common_type_t<quantity<Dimension, Rep1, Ratio1>, quantity<Dimension, Rep2, Ratio2>>
constexpr operator%(const quantity<Dimension, Rep1, Ratio1>& lhs,
const quantity<Dimension, Rep2, Ratio2>& rhs)
{
using ret = std::common_type_t<quantity<Dimension, Rep1, Ratio1>, quantity<Dimension, Rep2, Ratio2>>;
return ret(ret(lhs).count() % ret(rhs).count());
}
template<typename Dimension, typename Rep1, class Ratio1, typename Rep2, class Ratio2>
constexpr bool operator==(const quantity<Dimension, Rep1, Ratio1>& lhs,
const quantity<Dimension, Rep2, Ratio2>& rhs)
{
using ct = std::common_type_t<quantity<Dimension, Rep1, Ratio1>, quantity<Dimension, Rep2, Ratio2>>;
return ct(lhs).count() == ct(rhs).count();
}
template<typename Dimension, typename Rep1, class Ratio1, typename Rep2, class Ratio2>
constexpr bool operator!=(const quantity<Dimension, Rep1, Ratio1>& lhs,
const quantity<Dimension, Rep2, Ratio2>& rhs)
{
return !(lhs == rhs);
}
template<typename Dimension, typename Rep1, class Ratio1, typename Rep2, class Ratio2>
constexpr bool operator<(const quantity<Dimension, Rep1, Ratio1>& lhs,
const quantity<Dimension, Rep2, Ratio2>& rhs)
{
using ct = std::common_type_t<quantity<Dimension, Rep1, Ratio1>, quantity<Dimension, Rep2, Ratio2>>;
return ct(lhs).count() < ct(rhs).count();
}
template<typename Dimension, typename Rep1, class Ratio1, typename Rep2, class Ratio2>
constexpr bool operator<=(const quantity<Dimension, Rep1, Ratio1>& lhs,
const quantity<Dimension, Rep2, Ratio2>& rhs)
{
return !(rhs < lhs);
}
template<typename Dimension, typename Rep1, class Ratio1, typename Rep2, class Ratio2>
constexpr bool operator>(const quantity<Dimension, Rep1, Ratio1>& lhs,
const quantity<Dimension, Rep2, Ratio2>& rhs)
{
return rhs < lhs;
}
template<typename Dimension, typename Rep1, class Ratio1, typename Rep2, class Ratio2>
constexpr bool operator>=(const quantity<Dimension, Rep1, Ratio1>& lhs,
const quantity<Dimension, Rep2, Ratio2>& rhs)
{
return !(lhs < rhs);
}
// clang-format on
} // namespace units
namespace std {
// todo: simplified
template<typename Dimension, typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
struct common_type<units::quantity<Dimension, Rep1, Ratio1>, units::quantity<Dimension, Rep2, Ratio2>> {
using type =
units::quantity<Dimension, std::common_type_t<Rep1, Rep2>, mp::common_ratio_t<Ratio1, Ratio2>>;
};
} // namespace std

View File

@ -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

View File

@ -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<exp<base_dim_time, -1>>;
template<typename Rep, class Ratio = std::ratio<1>>
using frequency = quantity<dimension_frequency, Rep, Ratio>;
template<typename Rep>
using millihertzs = frequency<Rep, std::milli>;
template<typename Rep>
using hertzs = frequency<Rep>;
template<typename Rep>
using kilohertzs = frequency<Rep, std::kilo>;
template<typename Rep>
using megahertzs = frequency<Rep, std::mega>;
template<typename Rep>
using gigahertzs = frequency<Rep, std::giga>;
template<typename Rep>
using terahertzs = frequency<Rep, std::tera>;
// ...
namespace literals {
// mHz
constexpr auto operator""_mHz(unsigned long long l) { return millihertzs<std::int64_t>(l); }
constexpr auto operator""_mHz(long double l) { return millihertzs<long double>(l); }
// Hz
constexpr auto operator""_Hz(unsigned long long l) { return hertzs<std::int64_t>(l); }
constexpr auto operator""_Hz(long double l) { return hertzs<long double>(l); }
// kHz
constexpr auto operator""_kHz(unsigned long long l) { return kilohertzs<std::int64_t>(l); }
constexpr auto operator""_kHz(long double l) { return kilohertzs<long double>(l); }
// MHz
constexpr auto operator""_MHz(unsigned long long l) { return megahertzs<std::int64_t>(l); }
constexpr auto operator""_MHz(long double l) { return megahertzs<long double>(l); }
// GHz
constexpr auto operator""_GHz(unsigned long long l) { return gigahertzs<std::int64_t>(l); }
constexpr auto operator""_GHz(long double l) { return gigahertzs<long double>(l); }
// THz
constexpr auto operator""_THz(unsigned long long l) { return terahertzs<std::int64_t>(l); }
constexpr auto operator""_THz(long double l) { return terahertzs<long double>(l); }
} // namespace literals
} // namespace units

View File

@ -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<exp<base_dim_length, 1>>;
template<typename Rep, class Ratio = std::ratio<1>>
using length = quantity<dimension_length, Rep, Ratio>;
template<typename Rep>
using millimeters = length<Rep, std::milli>;
template<typename Rep>
using meters = length<Rep>;
template<typename Rep>
using kilometers = length<Rep, std::kilo>;
// ...
namespace literals {
// mm
constexpr auto operator""_mm(unsigned long long l) { return millimeters<std::int64_t>(l); }
constexpr auto operator""_mm(long double l) { return millimeters<long double>(l); }
// m
constexpr auto operator""_m(unsigned long long l) { return meters<std::int64_t>(l); }
constexpr auto operator""_m(long double l) { return meters<long double>(l); }
// km
constexpr auto operator""_km(unsigned long long l) { return kilometers<std::int64_t>(l); }
constexpr auto operator""_km(long double l) { return kilometers<long double>(l); }
} // namespace literals
} // namespace units

View File

@ -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<exp<base_dim_time, 1>>;
template<typename Rep, class Ratio = std::ratio<1>>
using time = quantity<dimension_time, Rep, Ratio>;
template<typename Rep>
using nanoseconds = time<Rep, std::nano>;
template<typename Rep>
using microseconds = time<Rep, std::micro>;
template<typename Rep>
using milliseconds = time<Rep, std::milli>;
template<typename Rep>
using seconds = time<Rep>;
template<typename Rep>
using minutes = time<Rep, std::ratio<60>>;
template<typename Rep>
using hours = time<Rep, std::ratio<3600>>;
// ...
namespace literals {
// ns
constexpr auto operator""_ns(unsigned long long l) { return nanoseconds<std::int64_t>(l); }
constexpr auto operator""_ns(long double l) { return nanoseconds<long double>(l); }
// us
constexpr auto operator""_us(unsigned long long l) { return microseconds<std::int64_t>(l); }
constexpr auto operator""_us(long double l) { return microseconds<long double>(l); }
// ms
constexpr auto operator""_ms(unsigned long long l) { return milliseconds<std::int64_t>(l); }
constexpr auto operator""_ms(long double l) { return milliseconds<long double>(l); }
// s
constexpr auto operator""_s(unsigned long long l) { return seconds<std::int64_t>(l); }
constexpr auto operator""_s(long double l) { return seconds<long double>(l); }
// min
constexpr auto operator""_min(unsigned long long l) { return minutes<std::int64_t>(l); }
constexpr auto operator""_min(long double l) { return minutes<long double>(l); }
// h
constexpr auto operator""_h(unsigned long long l) { return hours<std::int64_t>(l); }
constexpr auto operator""_h(long double l) { return hours<long double>(l); }
} // namespace literals
} // namespace units

View File

@ -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<base_dim_length, 1>, exp<base_dim_time, -1>>;
template<typename Rep, class Ratio = std::ratio<1>>
using velocity = quantity<dimension_velocity, Rep, Ratio>;
template<typename Rep>
using meters_per_second = velocity<Rep>;
template<typename Rep>
using kilometers_per_hour = velocity<Rep, std::ratio<1000, 3600>>;
template<typename Rep>
using miles_per_hour = velocity<Rep, std::ratio<44'704, 100'000>>;
// ...
namespace literals {
// mps
constexpr auto operator""_mps(unsigned long long l) { return meters_per_second<std::int64_t>(l); }
constexpr auto operator""_mps(long double l) { return meters_per_second<long double>(l); }
// kmph
constexpr auto operator""_kmph(unsigned long long l) { return kilometers_per_hour<std::int64_t>(l); }
constexpr auto operator""_kmph(long double l) { return kilometers_per_hour<long double>(l); }
// mph
constexpr auto operator""_mph(unsigned long long l) { return miles_per_hour<std::int64_t>(l); }
constexpr auto operator""_mph(long double l) { return miles_per_hour<long double>(l); }
} // namespace literals
} // namespace units

54
test/CMakeLists.txt Normal file
View File

@ -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
)

65
test/test_dimension.cpp Normal file
View File

@ -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 <gtest/gtest.h>
#include <utility>
using namespace units;
namespace {
template<int Id, int Value>
using e = exp<dim_id<Id>, Value>;
}
// make_dimension
static_assert(std::is_same_v<make_dimension_t<e<0, 1>>, dimension<e<0, 1>>>);
static_assert(std::is_same_v<make_dimension_t<e<0, 1>, e<1, 1>>, dimension<e<0, 1>, e<1, 1>>>);
static_assert(std::is_same_v<make_dimension_t<e<1, 1>, e<0, 1>>, dimension<e<0, 1>, e<1, 1>>>);
static_assert(std::is_same_v<make_dimension_t<e<1, 1>, e<1, 1>>, dimension<e<1, 2>>>);
static_assert(std::is_same_v<make_dimension_t<e<1, 1>, e<1, -1>>, dimension<detail::scalar>>);
static_assert(std::is_same_v<make_dimension_t<e<0, 1>, e<1, 1>, e<0, 1>, e<1, 1>>, dimension<e<0, 2>, e<1, 2>>>);
static_assert(std::is_same_v<make_dimension_t<e<0, -1>, e<1, -1>, e<0, -1>, e<1, -1>>, dimension<e<0, -2>, e<1, -2>>>);
static_assert(std::is_same_v<make_dimension_t<e<0, 1>, e<1, 1>, e<1, -1>>, dimension<e<0, 1>>>);
static_assert(std::is_same_v<make_dimension_t<e<0, 1>, e<0, -1>, e<1, 1>>, dimension<e<1, 1>>>);
static_assert(std::is_same_v<make_dimension_t<e<0, 1>, e<1, 1>, e<0, -1>>, dimension<e<1, 1>>>);
static_assert(std::is_same_v<make_dimension_t<e<0, 1>, e<1, 1>, e<0, -1>, e<1, -1>>, dimension<detail::scalar>>);
// dimension_multiply
static_assert(
std::is_same_v<dimension_multiply_t<dimension<e<0, 1>>, dimension<e<1, 1>>>, dimension<e<0, 1>, e<1, 1>>>);
static_assert(std::is_same_v<dimension_multiply_t<dimension<e<0, 1>, e<1, 1>, e<2, 1>>, dimension<e<3, 1>>>,
dimension<e<0, 1>, e<1, 1>, e<2, 1>, e<3, 1>>>);
static_assert(std::is_same_v<dimension_multiply_t<dimension<e<0, 1>, e<1, 1>, e<2, 1>>, dimension<e<1, 1>>>,
dimension<e<0, 1>, e<1, 2>, e<2, 1>>>);
static_assert(std::is_same_v<dimension_multiply_t<dimension<e<0, 1>, e<1, 1>, e<2, 1>>, dimension<e<1, -1>>>,
dimension<e<0, 1>, e<2, 1>>>);
// dimension_divide
static_assert(std::is_same_v<dimension_divide_t<dimension<e<0, 1>>, dimension<e<1, 1>>>, dimension<e<0, 1>, e<1, -1>>>);
static_assert(std::is_same_v<dimension_divide_t<dimension<e<0, 1>>, dimension<e<0, 1>>>, dimension<detail::scalar>>);

173
test/test_quantity.cpp Normal file
View File

@ -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 <gtest/gtest.h>
#include <utility>
using namespace units;
using namespace units::literals;
// is_quantity
static_assert(units::detail::is_quantity<millimeters<int>>::value);
// common_type
static_assert(std::is_same_v<std::common_type_t<meters<int>, kilometers<int>>, meters<int>>);
// constructors
constexpr quantity<dimension_length, int> kilometer{1000};
static_assert(kilometer.count() == 1000);
static_assert(length<int>(kilometer).count() == kilometer.count());
static_assert(meters<int>(kilometer).count() == kilometer.count());
static_assert(millimeters<int>(kilometer).count() == kilometer.count() * 1000);
static_assert(quantity_cast<kilometers<int>>(kilometer).count() == kilometer.count() / 1000);
//static_assert(meters<int>(1.0) == 1_m); // should not compile
static_assert(meters<int>(1) == 1_m);
static_assert(meters<float>(1.0) == 1_m);
static_assert(meters<float>(1) == 1_m);
//static_assert(kilometers<int>(1000_m) == 1000_m); // should not compile
static_assert(kilometers<float>(1000_m) == 1000_m);
//static_assert(meters<int>(meters<float>(1)) == 1_m); // should not compile
static_assert(meters<int>(quantity_cast<meters<int>>(meters<float>(1))) == 1_m);
// zero(), min(), max()
static_assert(length<int>::zero().count() == 0);
static_assert(length<int>::min().count() == std::numeric_limits<int>::min());
static_assert(length<int>::max().count() == std::numeric_limits<int>::max());
// unary member operators
static_assert((+1_m).count() == 1);
static_assert((-1_m).count() == -1);
// binary member operators
template<typename Dimension, typename Rep, class Ratio = std::ratio<1>>
constexpr auto post_inc(quantity<Dimension, Rep, Ratio> v)
{
auto vv = v++;
return std::make_pair(v, vv);
}
template<typename Dimension, typename Rep, class Ratio = std::ratio<1>>
constexpr auto pre_inc(quantity<Dimension, Rep, Ratio> v)
{
auto vv = ++v;
return std::make_pair(v, vv);
}
template<typename Dimension, typename Rep, class Ratio = std::ratio<1>>
constexpr auto post_dec(quantity<Dimension, Rep, Ratio> v)
{
auto vv = v--;
return std::make_pair(v, vv);
}
template<typename Dimension, typename Rep, class Ratio = std::ratio<1>>
constexpr auto pre_dec(quantity<Dimension, Rep, Ratio> 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<float>(2_kmph * 15_min).count() == 500_m); // should not compile
static_assert(kilometers<float>(2_kmph * 120.0_min).count() == 4);
static_assert(kilometers<float>(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<kilometers<int>>(2000_m) == 2_km);
// static_assert(quantity_cast<seconds<int>>(2_m) == 2_s); // should not compile

77
test/test_type_list.cpp Normal file
View File

@ -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 <gtest/gtest.h>
#include <utility>
using namespace mp;
using namespace units;
// type_list_push_front
static_assert(std::is_same_v<type_list_push_front_t<type_list<>, int>, type_list<int>>);
static_assert(std::is_same_v<type_list_push_front_t<type_list<>, int, long, double>, type_list<int, long, double>>);
static_assert(std::is_same_v<type_list_push_front_t<type_list<double>, int, long>, type_list<int, long, double>>);
// type_list_split_half
static_assert(std::is_same_v<type_list_split_half<type_list<int>>::first_list, type_list<int>>);
static_assert(std::is_same_v<type_list_split_half<type_list<int>>::second_list, type_list<>>);
static_assert(std::is_same_v<type_list_split_half<type_list<int, long>>::first_list, type_list<int>>);
static_assert(std::is_same_v<type_list_split_half<type_list<int, long>>::second_list, type_list<long>>);
static_assert(std::is_same_v<type_list_split_half<type_list<int, long, double>>::first_list, type_list<int, long>>);
static_assert(std::is_same_v<type_list_split_half<type_list<int, long, double>>::second_list, type_list<double>>);
static_assert(
std::is_same_v<type_list_split_half<type_list<int, long, double, float>>::first_list, type_list<int, long>>);
static_assert(
std::is_same_v<type_list_split_half<type_list<int, long, double, float>>::second_list, type_list<double, float>>);
// type_list_merge_sorted
static_assert(std::is_same_v<type_list_merge_sorted_t<type_list<dim_id<0>>, type_list<dim_id<1>>, dim_id_less>,
type_list<dim_id<0>, dim_id<1>>>);
static_assert(std::is_same_v<type_list_merge_sorted_t<type_list<dim_id<1>>, type_list<dim_id<0>>, dim_id_less>,
type_list<dim_id<0>, dim_id<1>>>);
static_assert(std::is_same_v<type_list_merge_sorted_t<type_list<dim_id<27>, dim_id<38>>,
type_list<dim_id<3>, dim_id<43>>, dim_id_less>,
type_list<dim_id<3>, dim_id<27>, dim_id<38>, dim_id<43>>>);
static_assert(
std::is_same_v<type_list_merge_sorted_t<type_list<dim_id<9>, dim_id<82>>, type_list<dim_id<10>>, dim_id_less>,
type_list<dim_id<9>, dim_id<10>, dim_id<82>>>);
// type_list_sort
static_assert(std::is_same_v<type_list_sort_t<type_list<dim_id<0>>, dim_id_less>, type_list<dim_id<0>>>);
static_assert(
std::is_same_v<type_list_sort_t<type_list<dim_id<0>, dim_id<1>>, dim_id_less>, type_list<dim_id<0>, dim_id<1>>>);
static_assert(
std::is_same_v<type_list_sort_t<type_list<dim_id<1>, dim_id<0>>, dim_id_less>, type_list<dim_id<0>, dim_id<1>>>);
static_assert(
std::is_same_v<
type_list_sort_t<type_list<dim_id<38>, 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<3>, dim_id<9>, dim_id<10>, dim_id<27>, dim_id<38>, dim_id<43>, dim_id<82>>>);

70
test/test_units.cpp Normal file
View File

@ -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 <gtest/gtest.h>
#include <utility>
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<decltype(1_km / 1_s), velocity<long long int, std::ratio<1000, 1>>>);
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<kilometers<int>>(2000_m) / 2_kmph == 1_h);