qxLib
base.inl
Go to the documentation of this file.
1 /**
2 
3  @file base.inl
4  @author Khrapov
5  @date 13.08.2025
6  @copyright © Nick Khrapov, 2025. All right reserved.
7 
8 **/
9 
10 namespace qx
11 {
12 
13 template<arithmetic_c T, unit_enum_c unit_t>
14 convert(T, unit_t) -> convert<T, unit_t>;
15 
16 template<arithmetic_c T, unit_enum_c unit_t>
17 convert(unit<T, unit_t>) -> convert<T, unit_t>;
18 
19 namespace units::details
20 {
21 
22 template<arithmetic_c T, unit_enum_c unit_t>
24 {
25 public:
26  constexpr base_converter(unit<T, unit_t> from) noexcept;
27  constexpr base_converter(T value, unit_t eFrom) noexcept;
28 
29 protected:
30  unit<T, unit_t> m_From;
31 };
32 
33 template<unit_enum_c unit_t, class char_t>
35 {
36  template<class format_context_type_t>
37  constexpr auto format(unit_t eData, format_context_type_t& ctx) const noexcept;
38 };
39 
40 } // namespace units::details
41 
42 } // namespace qx
43 
44 template<qx::arithmetic_c T, qx::unit_enum_c unit_t, class char_t>
45 struct std::formatter<qx::unit<T, unit_t>, char_t>
46 {
47  template<class format_parse_context_t>
48  constexpr auto parse(format_parse_context_t& context) noexcept;
49 
50  template<class format_context_type_t>
51  constexpr auto format(const qx::unit<T, unit_t>& unit, format_context_type_t& ctx) const noexcept;
52 
53 private:
54  std::formatter<T, char_t> valueFormatter;
55 };
56 
57 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
58 constexpr qx::unit<T, unit_t>::operator T() const noexcept
59 {
60  return value;
61 }
62 
63 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
64 constexpr bool qx::unit<T, unit_t>::operator==(const unit<T, unit_t>& other) const noexcept
65 {
66  if (type != other.type)
67  return false;
68 
69  if constexpr (std::is_floating_point_v<T>)
70  return float_compare(value, other.value);
71  else
72  return value == other.value;
73 }
74 
75 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
76 constexpr qx::units::details::base_converter<T, unit_t>::base_converter(unit<T, unit_t> from) noexcept : m_From(from)
77 {
78 }
79 
80 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
81 constexpr qx::units::details::base_converter<T, unit_t>::base_converter(T value, unit_t eFrom) noexcept
82  : m_From({ value, eFrom })
83 {
84 }
85 
86 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
87 constexpr qx::unit<T, unit_t> qx::normalize_unit(unit<T, unit_t> unit) noexcept
88 {
89  return units::traits<unit_t>::template normalize<T>(unit);
90 }
91 
92 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
93 constexpr qx::unit<T, unit_t> qx::normalize_unit(T value, unit_t eInitialType) noexcept
94 {
95  return qx::normalize_unit(unit { value, eInitialType });
96 }
97 
98 template<qx::arithmetic_c T, qx::unit_enum_c unit_t, class char_t>
99 std::optional<qx::unit<T, unit_t>> qx::unit_from_string(basic_string_view<char_t> svValue) noexcept
100 {
101  auto remove_suffix = [](basic_string_view<char_t> svValue,
102  auto predicate) -> std::optional<basic_string_view<char_t>>
103  {
104  size_t nToErase = predicate(svValue);
105  if (nToErase == 0)
106  return std::nullopt;
107 
108  svValue.remove_suffix(nToErase);
109  return svValue;
110  };
111 
112  auto trim_right = [&remove_suffix](basic_string_view<char_t> svValue)
113  {
114  while (std::optional<basic_string_view<char_t>> svErased = remove_suffix(
115  svValue,
116  [](basic_string_view<char_t> svValue)
117  {
118  size_t nToErase = 0;
119  while (string_traits::traits<char_t>::is_space(svValue[nToErase]))
120  {
121  ++nToErase;
122  }
123 
124  return nToErase;
125  }))
126  {
127  svValue = *svErased;
128  }
129 
130  return svValue;
131  };
132 
133  svValue = trim_right(svValue);
134 
135  const auto& suffixes = units::traits<unit_t>::template get_suffixes<char_t>();
136  auto itSuffix = suffixes.begin();
137  std::optional<unit_t> optUnitType;
138  std::optional<T> optValue;
139  while ((!optUnitType || !optValue) && itSuffix != suffixes.end())
140  {
141  auto optValueCandidate = remove_suffix(
142  svValue,
143  [&optUnitType, &itSuffix, &suffixes](basic_string_view<char_t> svValue) -> size_t
144  {
145  itSuffix = std::find_if(
146  itSuffix,
147  suffixes.end(),
148  [svValue](const std::pair<unit_t, basic_string_view<char_t>>& suffix)
149  {
150  return svValue.ends_with(suffix.second);
151  });
152 
153  if (itSuffix != suffixes.end())
154  {
155  optUnitType = itSuffix->first;
156  return itSuffix->second.size();
157  }
158  else
159  {
160  return 0;
161  }
162  });
163 
164  if (!optUnitType)
165  continue;
166 
167  if (!optValueCandidate)
168  continue;
169 
170  *optValueCandidate = trim_right(*optValueCandidate);
171 
172  // todo we can make it constexpr and get rid of a possible allocation
173  basic_string<char_t> sValue = *optValueCandidate;
174  optValue = sValue.template to<T>();
175  ++itSuffix;
176  }
177 
178  if (!optValue || !optUnitType)
179  return std::nullopt;
180 
181  return unit(*optValue, *optUnitType);
182 }
183 
184 template<qx::arithmetic_c T, qx::unit_enum_c unit_t, class char_t>
185 std::optional<qx::unit<T, unit_t>> qx::unit_from_string(const char_t* pszValue) noexcept
186 {
187  return unit_from_string<T, unit_t, char_t>(basic_string_view<char_t>(pszValue));
188 }
189 
190 
191 template<qx::unit_enum_c unit_t, class char_t>
192 constexpr std::optional<qx::basic_string_view<char_t>> qx::get_unit_suffix(unit_t eUnit) noexcept
193 {
194  const auto& suffixes = units::traits<unit_t>::template get_suffixes<char_t>();
195  auto itSuffix = std::ranges::find_if(
196  suffixes,
197  [eUnit](const std::pair<unit_t, basic_string_view<char_t>>& pair)
198  {
199  return pair.first == eUnit;
200  });
201  if (itSuffix != suffixes.end())
202  return itSuffix->second;
203  else
204  return std::nullopt;
205 }
206 
207 template<qx::arithmetic_c T, qx::unit_enum_c unit_t, class char_t>
208 template<class format_parse_context_t>
209 constexpr auto std::formatter<qx::unit<T, unit_t>, char_t>::parse(format_parse_context_t& context) noexcept
210 {
211  return valueFormatter.parse(context);
212 }
213 
214 
215 template<qx::arithmetic_c T, qx::unit_enum_c unit_t, class char_t>
216 template<class format_context_type_t>
217 constexpr auto std::formatter<qx::unit<T, unit_t>, char_t>::format(
218  const qx::unit<T, unit_t>& unit,
219  format_context_type_t& ctx) const noexcept
220 {
221  auto outIt = valueFormatter.format(unit.value, ctx);
222  return std::format_to(outIt, QX_STR_PREFIX(char_t, "{}"), unit.type);
223 }
224 
225 template<qx::unit_enum_c unit_t, class char_t>
226 template<class format_context_type_t>
227 constexpr auto qx::units::details::unit_formatter<unit_t, char_t>::format(unit_t eUnit, format_context_type_t& ctx)
228  const noexcept
229 {
230  auto out = ctx.out();
231 
232  if (std::optional<basic_string_view<char_t>> optSuffix = get_unit_suffix<unit_t, char_t>(eUnit))
233  out = std::format_to(out, QX_STR_PREFIX(char_t, "{}"), *optSuffix);
234 
235  return out;
236 }
constexpr unit< T, unit_t > normalize_unit(unit< T, unit_t > unit) noexcept
The function returns the closest value greater than one from the SI for the unit of measurement.
std::optional< unit< T, unit_t > > unit_from_string(basic_string_view< char_t > svValue) noexcept
Creates a unit from a string.
constexpr std::optional< basic_string_view< char_t > > get_unit_suffix(unit_t eUnit) noexcept
Get a unit suffix if exists.
#define QX_STR_PREFIX(value_t, str)
Chose witch of prefixes add to string : L or none.
Definition: string_utils.h:253
Definition: base.h:52