summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kelunit/distance/meter.h20
-rw-r--r--src/kelunit/time/second.h15
-rw-r--r--src/kelunit/unit.h49
-rw-r--r--src/kelunit/unit.tmpl.h53
-rw-r--r--src/kelunit/unit_print.h55
-rw-r--r--src/kelunit/unit_reduction.h133
6 files changed, 325 insertions, 0 deletions
diff --git a/src/kelunit/distance/meter.h b/src/kelunit/distance/meter.h
new file mode 100644
index 0000000..57ca58e
--- /dev/null
+++ b/src/kelunit/distance/meter.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "../unit.h"
+
+#include <string_view>
+
+namespace kelun {
+namespace unit_type {
+struct meter{
+ static constexpr std::string_view name = "meter";
+ static constexpr std::string_view short_name = "m";
+};
+}
+
+template<typename S>
+using meter = unit<S,unit_base<unit_type::meter,1>>;
+
+template<typename S>
+using square_meter = unit<S,unit_base<unit_type::meter,2>>;
+}
diff --git a/src/kelunit/time/second.h b/src/kelunit/time/second.h
new file mode 100644
index 0000000..07145ca
--- /dev/null
+++ b/src/kelunit/time/second.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "../unit.h"
+
+namespace kelun {
+namespace unit_type {
+struct second{
+ static constexpr std::string_view name = "second";
+ static constexpr std::string_view short_name = "s";
+};
+}
+
+template<typename S>
+using second = unit<S,unit_base<unit_type::second,1>>;
+}
diff --git a/src/kelunit/unit.h b/src/kelunit/unit.h
new file mode 100644
index 0000000..4958eb9
--- /dev/null
+++ b/src/kelunit/unit.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "./unit_reduction.h"
+
+namespace kelun {
+template<typename UnitType, int64_t Exponent>
+struct unit_base {};
+
+template<typename StorageT, typename... T>
+class unit;
+
+template<typename StorageT, typename... UnitTypes, int64_t... Exponents>
+class unit<StorageT, unit_base<UnitTypes, Exponents>...> {
+public:
+ using value_type = StorageT;
+
+ unit() = default;
+
+ unit(const unit<StorageT,unit_base<UnitTypes, Exponents>...>&) = default;
+ unit(unit<StorageT,unit_base<UnitTypes,Exponents>...>&&) = default;
+
+ unit<StorageT,unit_base<UnitTypes,Exponents>...>& operator=(const unit<StorageT,unit_base<UnitTypes,Exponents>...>&) = default;
+ unit<StorageT,unit_base<UnitTypes,Exponents>...>& operator=(unit<StorageT,unit_base<UnitTypes,Exponents>...>&&) = default;
+
+ unit(const value_type&);
+ unit(value_type&&);
+
+ unit<StorageT,unit_base<UnitTypes,Exponents>...>& operator=(const value_type&);
+ unit<StorageT,unit_base<UnitTypes,Exponents>...>& operator=(value_type&&);
+
+ unit<StorageT,unit_base<UnitTypes,Exponents>...> operator+(const unit<StorageT,unit_base<UnitTypes,Exponents>...>& rhs);
+ unit<StorageT,unit_base<UnitTypes,Exponents>...> operator-(const unit<StorageT,unit_base<UnitTypes,Exponents>...>& rhs);
+
+ template<typename... Trhs>
+ typename unit_multiplication<unit<StorageT,unit_base<UnitTypes,Exponents>...>, unit<StorageT,Trhs...>>::type operator*(const unit<StorageT, Trhs...>& rhs);
+
+ template<typename... Trhs>
+ typename unit_multiplication<unit<StorageT, unit_base<UnitTypes,Exponents>...>, typename unit_invert<StorageT,Trhs...>::type>::type operator/(const unit<StorageT, Trhs...>& rhs);
+
+ value_type data() const;
+private:
+ value_type value;
+};
+
+template<typename S>
+using scalar = unit<S>;
+}
+
+#include "unit.tmpl.h"
diff --git a/src/kelunit/unit.tmpl.h b/src/kelunit/unit.tmpl.h
new file mode 100644
index 0000000..42b96ef
--- /dev/null
+++ b/src/kelunit/unit.tmpl.h
@@ -0,0 +1,53 @@
+#include <utility>
+
+namespace kelun {
+
+template<typename StorageT, typename... UnitTypes, int64_t... Exponents>
+unit<StorageT,unit_base<UnitTypes, Exponents>...>::unit(const value_type& value_):
+ value{value_}{}
+
+template<typename StorageT, typename... UnitTypes, int64_t... Exponents>
+unit<StorageT,unit_base<UnitTypes, Exponents>...>::unit(value_type&& value_):value{std::move(value_)}{}
+
+template<typename StorageT, typename... UnitTypes, int64_t... Exponents>
+unit<StorageT,unit_base<UnitTypes, Exponents>...>& unit<StorageT,unit_base<UnitTypes, Exponents>...>::operator=(const typename unit<StorageT,unit_base<UnitTypes, Exponents>...>::value_type& value_){
+ value = value_;
+ return *this;
+}
+
+template<typename StorageT, typename... UnitTypes, int64_t... Exponents>
+unit<StorageT,unit_base<UnitTypes, Exponents>...>& unit<StorageT,unit_base<UnitTypes, Exponents>...>::operator=(typename unit<StorageT,unit_base<UnitTypes, Exponents>...>::value_type&& value_){
+ value = std::move(value_);
+ return *this;
+}
+
+template<typename StorageT, typename... UnitTypes, int64_t... Exponents>
+unit<StorageT,unit_base<UnitTypes, Exponents>...> unit<StorageT,unit_base<UnitTypes, Exponents>...>::operator+(const unit<StorageT,unit_base<UnitTypes, Exponents>...>& rhs){
+ return value + rhs.value;
+}
+
+template<typename StorageT, typename... UnitTypes, int64_t... Exponents>
+unit<StorageT,unit_base<UnitTypes, Exponents>...> unit<StorageT,unit_base<UnitTypes, Exponents>...>::operator-(const unit<StorageT,unit_base<UnitTypes, Exponents>...>& rhs){
+ return value - rhs.value;
+}
+
+template<typename StorageT, typename... UnitTypes, int64_t... Exponents>
+template<typename... Trhs>
+typename unit_multiplication<unit<StorageT,unit_base<UnitTypes,Exponents>...>, unit<StorageT, Trhs...>>::type
+unit<StorageT,unit_base<UnitTypes, Exponents>...>::operator*(const unit<StorageT,Trhs...>& rhs){
+ return value * rhs.data();
+}
+
+template<typename StorageT, typename... UnitTypes, int64_t... Exponents>
+template<typename... Trhs>
+typename unit_multiplication<unit<StorageT,unit_base<UnitTypes,Exponents>...>, typename unit_invert<StorageT,Trhs...>::type>::type
+unit<StorageT,unit_base<UnitTypes,Exponents>...>::operator/(const unit<StorageT, Trhs...>& rhs){
+ typename unit_invert<StorageT, Trhs...>::type rhs_inverted{static_cast<StorageT>(1)/rhs.data()};
+ return value * rhs_inverted.data();
+}
+
+template<typename StorageT, typename... UnitTypes, int64_t... Exponents>
+typename unit<StorageT,unit_base<UnitTypes, Exponents>...>::value_type unit<StorageT,unit_base<UnitTypes, Exponents>...>::data() const {
+ return value;
+}
+}
diff --git a/src/kelunit/unit_print.h b/src/kelunit/unit_print.h
new file mode 100644
index 0000000..0f3cb72
--- /dev/null
+++ b/src/kelunit/unit_print.h
@@ -0,0 +1,55 @@
+#include "./unit.h"
+
+#include <iostream>
+
+
+namespace std {
+template<typename UnitT, int64_t UnitE>
+inline ostream& operator<<(ostream& o, const kelun::unit_base<UnitT,UnitE>& ele){
+ o<<UnitT::short_name;
+ if constexpr ( UnitE != 1 ){
+ o<<'^'<<'('<<UnitE<<')';
+ }
+ return o;
+}
+}
+
+namespace kelun {
+template<typename... T>
+struct unit_print_impl {
+ static_assert(is_always_false<T...>, "Template type not supported");
+};
+
+template<typename UnitT, int64_t UnitE, typename... UnitTL, int64_t... UnitEL>
+struct unit_print_impl<unit_base<UnitT,UnitE>,unit_base<UnitTL,UnitEL>...> {
+ static std::ostream& print(std::ostream& o){
+
+ unit_base<UnitT,UnitE> element;
+
+ std::ostream& o_ret = o << element;
+
+ if constexpr (sizeof...(UnitTL) > 0){
+ std::ostream& o_ret_next = o_ret << ' ' << '*' << ' ';
+ return unit_print_impl<unit_base<UnitTL,UnitEL>...>::print(o_ret_next);
+ }
+
+ return o_ret<<']';
+ }
+};
+}
+
+namespace std {
+
+template<typename StorageT, typename... T>
+inline ostream& operator<<(ostream& o, const kelun::unit<StorageT,T...>& unit);
+
+template<typename StorageT, typename... UnitT, int64_t... UnitE>
+inline ostream& operator<<(ostream& o, const kelun::unit<StorageT,kelun::unit_base<UnitT,UnitE>...>& unit){
+ o << unit.data();
+ if constexpr (sizeof...(UnitT) > 0) {
+ auto& o_ret = o << ' '<<'[';
+ return kelun::unit_print_impl<kelun::unit_base<UnitT,UnitE>...>::print(o_ret);
+ }
+ return o;
+}
+}
diff --git a/src/kelunit/unit_reduction.h b/src/kelunit/unit_reduction.h
new file mode 100644
index 0000000..d3299ff
--- /dev/null
+++ b/src/kelunit/unit_reduction.h
@@ -0,0 +1,133 @@
+#pragma once
+
+#include <cstdint>
+#include <type_traits>
+
+namespace kelun {
+template<typename... T>
+constexpr bool is_always_false = false;
+
+template<typename UnitType, int64_t Exponent>
+struct unit_base;
+
+template<typename StorageT, typename... T>
+class unit;
+
+namespace impl {
+
+template<typename T, typename U>
+class unit_matching;
+
+template<typename... T>
+class unit_redux_list {
+ static_assert(sizeof...(T) == 0, "Template type not supported");
+
+ using reduced_typed = unit_redux_list<>;
+};
+
+template<typename T0, int64_t E0, typename... TL, int64_t... EL>
+struct unit_redux_list<unit_base<T0,E0>, unit_base<TL,EL>...> {
+ using reduced_type = typename unit_matching<unit_redux_list<unit_base<T0,E0>, unit_base<TL,EL>...>, unit_redux_list<>>::type;
+};
+
+template<typename T, typename U, typename V>
+class unit_matching_reduce {
+public:
+ static_assert(is_always_false<T, U, V>, "Template type not supported");
+};
+
+template<typename T, int64_t E, typename T0, int64_t E0, typename... TL, int64_t... EL, typename... TR, int64_t... ER>
+class unit_matching_reduce<unit_base<T,E>, unit_redux_list<unit_base<T0,E0>,unit_base<TL,EL>...>, unit_redux_list<unit_base<TR,ER>...>> {
+public:
+ static constexpr bool is_same = std::is_same_v<T,T0>;
+
+ using match_reduce_type = typename std::conditional<is_same, unit_base<T,E+E0>, unit_base<T,E>>::type;
+ using match_reduce_unit_redux_list = typename std::conditional<is_same, unit_redux_list<unit_base<TR,ER>...>, unit_redux_list<unit_base<TR,ER>..., unit_base<T0,E0>>>::type;
+
+ using value_type = typename unit_matching_reduce<match_reduce_type, unit_redux_list<unit_base<TL,EL>...>, match_reduce_unit_redux_list>::value_type;
+ using unit_redux_list_type = typename unit_matching_reduce<match_reduce_type, unit_redux_list<unit_base<TL,EL>...>, match_reduce_unit_redux_list>::unit_redux_list_type;
+
+ static constexpr int64_t value_num = unit_matching_reduce<match_reduce_type, unit_redux_list<unit_base<TL,EL>...>, match_reduce_unit_redux_list>::value_num;
+};
+
+template<typename T, int64_t E, typename... TR, int64_t... ER>
+class unit_matching_reduce<unit_base<T,E>, unit_redux_list<>, unit_redux_list<unit_base<TR,ER>...>> {
+public:
+ using value_type = unit_base<T,E>;
+ using unit_redux_list_type = unit_redux_list<unit_base<TR,ER>...>;
+
+ static constexpr int64_t value_num = E;
+};
+
+template<typename T, typename U>
+class unit_matching {
+ static_assert(is_always_false<T, U>, "Template type not supported");
+};
+
+template<typename... T, int64_t... E>
+class unit_matching<unit_redux_list<>,unit_redux_list<unit_base<T,E>...>> {
+public:
+ using type = unit_redux_list<unit_base<T,E>...>;
+
+};
+
+template<typename T0, int64_t E0, typename... TL, int64_t... EL, typename... TR, int64_t... ER>
+class unit_matching<unit_redux_list<unit_base<T0,E0>,unit_base<TL,EL>...>, unit_redux_list<unit_base<TR,ER>...>> {
+public:
+ using reduced_value_type = typename unit_matching_reduce<unit_base<T0,E0>, unit_redux_list<unit_base<TL,EL>...>, unit_redux_list<>>::value_type;
+ using reduced_unit_redux_list_type = typename unit_matching_reduce<unit_base<T0,E0>, unit_redux_list<unit_base<TL,EL>...>, unit_redux_list<>>::unit_redux_list_type;
+
+ static constexpr int64_t reduced_value_num = unit_matching_reduce<unit_base<T0,E0>, unit_redux_list<unit_base<TL,EL>...>, unit_redux_list<>>::value_num;
+ using reduced_result_unit_redux_list = typename std::conditional<reduced_value_num == 0, unit_redux_list<unit_base<TR,ER>...>, unit_redux_list<unit_base<TR,ER>...,reduced_value_type>>::type;
+
+ using type = typename unit_matching<reduced_unit_redux_list_type, reduced_result_unit_redux_list>::type;
+};
+
+template<typename List, typename StorageT>
+class unit_matching_add_storage {
+public:
+ static_assert(is_always_false<List,StorageT>, "Template type not supported");
+};
+
+template<typename StorageT, typename... UnitTypes, int64_t... UnitExponents>
+class unit_matching_add_storage<unit_redux_list<unit_base<UnitTypes,UnitExponents>...>, StorageT> {
+public:
+ using type = unit<StorageT, unit_base<UnitTypes,UnitExponents>...>;
+};
+
+}
+
+template<typename StorageT, typename... T>
+class unit_reduction {
+ static_assert(is_always_false<StorageT,T...>, "Template type not supported");
+};
+
+template<typename StorageT, typename... UnitT, int64_t... UnitE>
+class unit_reduction<StorageT, unit_base<UnitT, UnitE>...> {
+public:
+ using list_type = typename impl::unit_matching<impl::unit_redux_list<unit_base<UnitT, UnitE>...>, impl::unit_redux_list<>>::type;
+ using type = typename impl::unit_matching_add_storage<list_type, StorageT>::type;
+};
+
+template<typename StorageT, typename... T>
+class unit_invert {
+ static_assert(is_always_false<StorageT, T...>, "Template type not supported");
+};
+
+template<typename StorageT, typename... UnitT, int64_t... UnitE>
+class unit_invert<StorageT, unit_base<UnitT, UnitE>...> {
+public:
+ using type = unit<StorageT, unit_base<UnitT, -UnitE>...>;
+};
+
+template<typename T, typename U>
+class unit_multiplication{
+ static_assert(is_always_false<T, U>, "Template type not supported");
+};
+
+template<typename StorageT, typename... UnitT, int64_t... UnitE, typename... UnitRhsT, int64_t... UnitRhsE>
+class unit_multiplication<unit<StorageT, unit_base<UnitT,UnitE>...>, unit<StorageT, unit_base<UnitRhsT, UnitRhsE>...>> {
+public:
+ using type = typename unit_reduction<StorageT, unit_base<UnitT,UnitE>..., unit_base<UnitRhsT, UnitRhsE>...>::type;
+};
+}