|
| 1 | +{% extends "generic/unit_system.template_local" %} |
| 2 | + |
| 3 | +{% block include_area %} |
| 4 | +{{ super() }} |
| 5 | + |
| 6 | +#if __cplusplus < 202002L |
| 7 | + #error "C++ 20 support is required" |
| 8 | +#endif |
| 9 | + |
| 10 | + |
| 11 | +#ifndef UNIT_SYSTEM_DEFAULT_TYPE |
| 12 | + #define UNIT_SYSTEM_DEFAULT_TYPE long double |
| 13 | +#endif |
| 14 | + |
| 15 | +#include <algorithm> |
| 16 | +#include <chrono> |
| 17 | +#include <cmath> |
| 18 | +#include <concepts> |
| 19 | +#include <iostream> |
| 20 | +#include <ratio> |
| 21 | + |
| 22 | +#ifndef UNIT_SYSTEM_EXPORT_MACRO |
| 23 | + #define UNIT_SYSTEM_EXPORT_MACRO |
| 24 | +#endif |
| 25 | +{%endblock%} |
| 26 | + |
| 27 | +{% block base_class_area %} |
| 28 | +namespace sakurajin{ |
| 29 | + namespace unit_system{ |
| 30 | + |
| 31 | + {% for unit in units %} |
| 32 | + template <std::floating_point base_type> |
| 33 | + class {{ unit.name }}_t { |
| 34 | + private: |
| 35 | + base_type value{static_cast<base_type>(0.0)}; |
| 36 | + base_type multiplier{static_cast<base_type>(1.0)}; |
| 37 | + base_type offset{static_cast<base_type>(0.0)}; |
| 38 | + base_type rel_error{static_cast<base_type>(0.000001)}; |
| 39 | + |
| 40 | + public: |
| 41 | + {{ unit.name }}_t() = default; |
| 42 | + {{ unit.name }}_t(const {{ unit.name }}_t& other) = default; |
| 43 | + |
| 44 | + template <class value_t = base_type, class mult_t = base_type, class offset_t = base_type> |
| 45 | + requires std::convertible_to<value_t, base_type> && std::convertible_to<mult_t, base_type> && std::convertible_to<offset_t, base_type> |
| 46 | + explicit {{ unit.name }}_t(value_t v, mult_t mult = 1.0, offset_t off = 0.0) |
| 47 | + : value{static_cast<base_type>(v)}, multiplier{static_cast<base_type>(mult)}, offset{static_cast<base_type>(off)} {} |
| 48 | + |
| 49 | + template<std::intmax_t numerator, std::intmax_t denumerator = 1, class value_t = base_type, class offset_t = base_type> |
| 50 | + explicit {{ unit.name }}_t(value_t v, std::ratio<numerator, denumerator>, offset_t off = 0.0): {{unit.name}}_t{ |
| 51 | + v, static_cast<long double>(numerator)/static_cast<long double>(denumerator), off |
| 52 | + }{} |
| 53 | + |
| 54 | + |
| 55 | + base_type val() const { return value; } |
| 56 | + base_type mult() const { return multiplier; } |
| 57 | + base_type off() const { return offset; } |
| 58 | + base_type rel_err() const { return rel_error; } |
| 59 | + |
| 60 | + base_type& val() { return value; } |
| 61 | + base_type& mult() { return multiplier; } |
| 62 | + base_type& off() { return offset; } |
| 63 | + base_type& rel_err() { return rel_error; } |
| 64 | + |
| 65 | + |
| 66 | + template <class scalar_t> requires std::convertible_to<scalar_t, base_type> |
| 67 | + {{ unit.name }}_t<base_type> operator*(scalar_t scalar) const { |
| 68 | + return {{ unit.name }}_t<base_type>{value * static_cast<base_type>(scalar), multiplier, offset}; |
| 69 | + }; |
| 70 | + |
| 71 | + template <class scalar_t> requires std::convertible_to<scalar_t, base_type> |
| 72 | + void operator*=(scalar_t scalar) { value *= static_cast<base_type>(scalar); } |
| 73 | + |
| 74 | + template <class scalar_t> requires std::convertible_to<scalar_t, base_type> |
| 75 | + {{ unit.name }}_t<base_type> operator/(scalar_t scalar) const { |
| 76 | + return {{ unit.name }}_t<base_type>{value / static_cast<base_type>(scalar), multiplier, offset}; |
| 77 | + } |
| 78 | + template <class scalar_t> requires std::convertible_to<scalar_t, base_type> |
| 79 | + void operator/=(scalar_t scalar) { value /= static_cast<base_type>(scalar); } |
| 80 | + |
| 81 | + |
| 82 | + long double operator/(const {{ unit.name }}_t& other) const { |
| 83 | + return static_cast<long double>(this->value) / static_cast<long double>(other.convert_like(*this).val()); |
| 84 | + } |
| 85 | + |
| 86 | + {{ unit.name }}_t operator+(const {{ unit.name }}_t& other) const { |
| 87 | + auto retval = other.convert_like(*this); |
| 88 | + retval.val() += this->value; |
| 89 | + return retval; |
| 90 | + } |
| 91 | + void operator+=(const {{ unit.name }}_t& other) { |
| 92 | + auto retval = other.convert_like(*this); |
| 93 | + this->value += retval.val(); |
| 94 | + } |
| 95 | + |
| 96 | + {{ unit.name }}_t operator-(const {{ unit.name }}_t& other) const { |
| 97 | + auto retval = this->convert_like(other); |
| 98 | + retval.val() -= other.val(); |
| 99 | + return retval; |
| 100 | + } |
| 101 | + void operator-=(const {{ unit.name }}_t& other) { |
| 102 | + auto retval = other.convert_like(*this); |
| 103 | + this->value -= retval.val(); |
| 104 | + } |
| 105 | + |
| 106 | + {{ unit.name }}_t operator-() const { return {{ unit.name }}_t{-value, multiplier, offset}; } |
| 107 | + |
| 108 | + {{ unit.name }}_t& operator=(const {{ unit.name }}_t& other) = default; |
| 109 | + |
| 110 | + explicit operator long double() const{ |
| 111 | + return convert_copy(1.0, 0.0).val(); |
| 112 | + } |
| 113 | + |
| 114 | + template <class mult_t = base_type, class offset_t = base_type> |
| 115 | + requires std::convertible_to<mult_t, base_type> && std::convertible_to<offset_t, base_type> |
| 116 | + [[nodiscard]]{{ unit.name }}_t convert_copy(mult_t new_multiplier, offset_t new_offset) const { |
| 117 | + auto new_mult = static_cast<base_type>(new_multiplier); |
| 118 | + auto new_off = static_cast<base_type>(new_offset); |
| 119 | + auto new_val = (value * multiplier + (offset - new_off)) / new_mult; |
| 120 | + return {{ unit.name }}_t{new_val, new_mult, new_off}; |
| 121 | + } |
| 122 | + |
| 123 | + template <class mult_t = base_type> |
| 124 | + requires std::convertible_to<mult_t, base_type> |
| 125 | + [[nodiscard]] |
| 126 | + auto convert_multiplier(mult_t new_multiplier) const { |
| 127 | + return convert_copy(new_multiplier, this->offset); |
| 128 | + } |
| 129 | + |
| 130 | + template <class offset_t = base_type> |
| 131 | + requires std::convertible_to<offset_t, base_type> |
| 132 | + [[nodiscard]] |
| 133 | + auto convert_offset(offset_t new_offset) const { |
| 134 | + return convert_copy(this->multiplier, new_offset); |
| 135 | + } |
| 136 | + |
| 137 | + // returns a copy of the unit with the same multiplier and offset as the other unit |
| 138 | + [[nodiscard]] |
| 139 | + auto convert_like(const {{ unit.name }}_t& other) const { |
| 140 | + return convert_copy(other.mult(), other.off()); |
| 141 | + } |
| 142 | + |
| 143 | + auto operator<=>(const {{ unit.name }}_t& other) const { return this->val() <=> other.convert_like(*this).val(); } |
| 144 | + |
| 145 | + auto operator==(const {{ unit.name }}_t& other) const { return this->val() == other.convert_like(*this).val(); } |
| 146 | + auto operator!=(const {{ unit.name }}_t& other) const { return this->val() != other.convert_like(*this).val(); } |
| 147 | + }; |
| 148 | + |
| 149 | + |
| 150 | + template <std::floating_point base_type, class sclar_t> |
| 151 | + requires std::convertible_to<sclar_t, base_type> |
| 152 | + {{ unit.name }}_t<base_type> operator*(sclar_t scalar, const {{ unit.name }}_t<base_type>& value) { |
| 153 | + return value * scalar; |
| 154 | + } |
| 155 | + |
| 156 | + template <std::floating_point base_type, class mult_t = base_type, class offset_t = base_type> |
| 157 | + requires std::convertible_to<mult_t, base_type> && std::convertible_to<offset_t, base_type> |
| 158 | + {{ unit.name }}_t<base_type> unit_cast(const {{ unit.name }}_t<base_type>& unit, mult_t new_multiplier = 1, offset_t new_offset = 0) { |
| 159 | + return unit.convert_copy(new_multiplier, new_offset); |
| 160 | + } |
| 161 | + |
| 162 | + template <std::floating_point base_type> |
| 163 | + {{ unit.name }}_t<base_type> clamp(const {{ unit.name }}_t<base_type>& unit, const {{ unit.name }}_t<base_type>& lower, const {{ unit.name }}_t<base_type>& upper) { |
| 164 | + auto low = lower.convert_like(unit); |
| 165 | + auto high = upper.convert_like(unit); |
| 166 | + return {{ unit.name }}_t<base_type>{std::clamp(unit.val(), low.val(), high.val()), unit.mult(), unit.off()}; |
| 167 | + } |
| 168 | + |
| 169 | + template <std::floating_point base_type> |
| 170 | + std::ostream& operator<<(std::ostream& os, const {{ unit.name }}_t<base_type>& val) { |
| 171 | + auto val_raw = val.convert_copy(1.0, 0.0); |
| 172 | + return os << val_raw.val() << " {{ base_name }}"; |
| 173 | + } |
| 174 | + |
| 175 | + {% endfor %} |
| 176 | + |
| 177 | + //define all unit combination operators |
| 178 | + {% for unit in units %} |
| 179 | + |
| 180 | + {% if unit.divisions|length > 0 %}{% for div in unit.divisions %} |
| 181 | + template <std::floating_point base_type> |
| 182 | + [[nodiscard]]auto operator/(const {{ unit.name }}_t<base_type>& val, const {{ div.divisor }}_t<base_type>& other){ |
| 183 | + auto _v1 = val.convert_offset(0); |
| 184 | + auto _v2 = other.convert_offset(0); |
| 185 | + return sakurajin::unit_system::{{ div.result }}_t<base_type>{_v1.val()/_v2.val(),_v1.mult()/_v2.mult()}; |
| 186 | + } |
| 187 | + {% endfor %}{% endif %} |
| 188 | + |
| 189 | + {% if unit.multiplications|length > 0 %}{% for mult in unit.multiplications %} |
| 190 | + template <std::floating_point base_type> |
| 191 | + [[nodiscard]]auto operator*(const {{ unit.name }}_t<base_type>& val, const {{ mult.factor }}_t<base_type>& other){ |
| 192 | + auto _v1 = val.convert_offset(0); |
| 193 | + auto _v2 = other.convert_offset(0); |
| 194 | + return sakurajin::unit_system::{{ mult.product }}_t<base_type>{_v1.val()*_v2.val(),_v1.mult()/_v2.mult()}; |
| 195 | + } |
| 196 | + {% endfor %}{% endif %} |
| 197 | + |
| 198 | + {% if unit.square_result != '' %} |
| 199 | + template <std::floating_point base_type> |
| 200 | + [[nodiscard]]auto square(const {{ unit.name }}_t<base_type>& val) {return val*val;}{% endif %} |
| 201 | + |
| 202 | + {% if unit.sqrt_result != '' %} |
| 203 | + template <std::floating_point base_type> |
| 204 | + [[nodiscard]]auto sqrt(const {{ unit.name }}_t<base_type>& val){ |
| 205 | + return sakurajin::unit_system::{{ unit.sqrt_result }}_t<base_type>{ {{ extra_data.sqrt_function }}(val.val()), {{ extra_data.sqrt_function }}(val.mult()), val.off()}; |
| 206 | + } |
| 207 | + {% endif %} |
| 208 | + |
| 209 | + {% endfor %} |
| 210 | + |
| 211 | + //forward declare all units |
| 212 | + {% for unit in units %} |
| 213 | + UNIT_SYSTEM_EXPORT_MACRO typedef {{ unit.name }}_t<UNIT_SYSTEM_DEFAULT_TYPE> {{ unit.name }}; |
| 214 | + {% endfor %} |
| 215 | + |
| 216 | + |
| 217 | + //define all literals |
| 218 | + inline namespace literals{ |
| 219 | + {% for unit in units %} |
| 220 | + {% if unit.literals|length > 0 %} |
| 221 | + {% for literal in unit.literals %} |
| 222 | + {{ extra_data.export_macro }} auto operator "" _{{ literal.code_literal }}(long double val){ |
| 223 | + return sakurajin::unit_system::{{ unit.name }}{val,{{ literal.multiplier }}, {{ literal.offset }}}; |
| 224 | + } |
| 225 | + {{ extra_data.export_macro }} auto operator "" _{{ literal.code_literal }}(unsigned long long int val){ |
| 226 | + return sakurajin::unit_system::{{ unit.name }}{static_cast<long double>(val),{{ literal.multiplier }}, {{ literal.offset }}}; |
| 227 | + } |
| 228 | + {% endfor %} |
| 229 | + {% endif %}{% endfor %} |
| 230 | + } |
| 231 | + } |
| 232 | +} |
| 233 | +{%endblock%} |
| 234 | + |
| 235 | +{% block std_compat %}{% if extra_data.has_std %} |
| 236 | +namespace std{ |
| 237 | + {% for unit in units %} |
| 238 | + template <std::floating_point base_type> |
| 239 | + sakurajin::unit_system::{{ unit.name }}_t<base_type> abs(const sakurajin::unit_system::{{ unit.name }}_t<base_type>& unit){ |
| 240 | + const auto raw_val = unit.val(); |
| 241 | + const auto inv_val = -raw_val; |
| 242 | + const auto abs_val = (raw_val > inv_val) ? raw_val : inv_val; |
| 243 | + return sakurajin::unit_system::{{ unit.name }}_t<base_type>{abs_val, unit.mult(), unit.off()}; |
| 244 | + } |
| 245 | + {% endfor %} |
| 246 | +} |
| 247 | + |
| 248 | + |
| 249 | +//add compatibility with std::chrono |
| 250 | +namespace sakurajin{ |
| 251 | + namespace unit_system{ |
| 252 | + template<class Rep, class Period = std::ratio<1> > |
| 253 | + time_si unit_cast(const std::chrono::duration<Rep, Period>& other, auto new_multiplier = 1.0){ |
| 254 | + auto t = std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1,1>>>(other); |
| 255 | + auto retval = time_si{t.count(), 1}; |
| 256 | + return retval.convert_multiplier(new_multiplier); |
| 257 | + } |
| 258 | + } |
| 259 | +} |
| 260 | +{% endif %}{% endblock %} |
0 commit comments