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 (c) 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 -> decltype(ctx.out());
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 QX_FMT_NS::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  -> decltype(ctx.out());
53 
54 private:
55  QX_FMT_NS::formatter<T, char_t> m_ValueFormatter;
56 };
57 
58 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
59 constexpr qx::unit<T, unit_t>::operator T() const noexcept
60 {
61  return value;
62 }
63 
64 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
65 constexpr bool qx::unit<T, unit_t>::operator==(const unit<T, unit_t>& other) const noexcept
66 {
67  if (type != other.type)
68  return false;
69 
70  if constexpr (std::is_floating_point_v<T>)
71  return float_compare(value, other.value);
72  else
73  return value == other.value;
74 }
75 
76 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
77 constexpr qx::units::details::base_converter<T, unit_t>::base_converter(unit<T, unit_t> from) noexcept : m_From(from)
78 {
79 }
80 
81 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
82 constexpr qx::units::details::base_converter<T, unit_t>::base_converter(T value, unit_t eFrom) noexcept
83  : m_From({ value, eFrom })
84 {
85 }
86 
87 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
88 constexpr qx::unit<T, unit_t> qx::normalize_unit(unit<T, unit_t> unit) noexcept
89 {
90  return units::traits<unit_t>::template normalize<T>(unit);
91 }
92 
93 template<qx::arithmetic_c T, qx::unit_enum_c unit_t>
94 constexpr qx::unit<T, unit_t> qx::normalize_unit(T value, unit_t eInitialType) noexcept
95 {
96  return qx::normalize_unit(unit { value, eInitialType });
97 }
98 
99 template<qx::arithmetic_c T, qx::unit_enum_c unit_t, class char_t>
100 std::optional<qx::unit<T, unit_t>> qx::unit_from_string(basic_string_view<char_t> svValue) noexcept
101 {
102  auto remove_suffix = [](basic_string_view<char_t> svValue,
103  auto predicate) -> std::optional<basic_string_view<char_t>>
104  {
105  size_t nToErase = predicate(svValue);
106  if (nToErase == 0)
107  return std::nullopt;
108 
109  svValue.remove_suffix(nToErase);
110  return svValue;
111  };
112 
113  auto trim_right = [&remove_suffix](basic_string_view<char_t> svValue)
114  {
115  while (std::optional<basic_string_view<char_t>> svErased = remove_suffix(
116  svValue,
117  [](basic_string_view<char_t> svValue)
118  {
119  size_t nToErase = 0;
120  while (string_traits::default_traits<char_t>::is_space(svValue[nToErase]))
121  {
122  ++nToErase;
123  }
124 
125  return nToErase;
126  }))
127  {
128  svValue = *svErased;
129  }
130 
131  return svValue;
132  };
133 
134  svValue = trim_right(svValue);
135 
136  const auto& suffixes = units::traits<unit_t>::template get_suffixes<char_t>();
137  auto itSuffix = suffixes.begin();
138  std::optional<unit_t> optUnitType;
139  std::optional<T> optValue;
140  while ((!optUnitType || !optValue) && itSuffix != suffixes.end())
141  {
142  auto optValueCandidate = remove_suffix(
143  svValue,
144  [&optUnitType, &itSuffix, &suffixes](basic_string_view<char_t> svValue) -> size_t
145  {
146  itSuffix = std::find_if(
147  itSuffix,
148  suffixes.end(),
149  [svValue](const std::pair<unit_t, basic_string_view<char_t>>& suffix)
150  {
151  return svValue.ends_with(suffix.second);
152  });
153 
154  if (itSuffix != suffixes.end())
155  {
156  optUnitType = itSuffix->first;
157  return itSuffix->second.size();
158  }
159  else
160  {
161  return 0;
162  }
163  });
164 
165  if (!optUnitType)
166  continue;
167 
168  if (!optValueCandidate)
169  continue;
170 
171  *optValueCandidate = trim_right(*optValueCandidate);
172 
173  // todo we can make it constexpr and get rid of a possible allocation
174  basic_string<char_t> sValue = *optValueCandidate;
175  optValue = sValue.template to<T>();
176  ++itSuffix;
177  }
178 
179  if (!optValue || !optUnitType)
180  return std::nullopt;
181 
182  return unit(*optValue, *optUnitType);
183 }
184 
185 template<qx::arithmetic_c T, qx::unit_enum_c unit_t, class char_t>
186 std::optional<qx::unit<T, unit_t>> qx::unit_from_string(const char_t* pszValue) noexcept
187 {
188  return unit_from_string<T, unit_t, char_t>(basic_string_view<char_t>(pszValue));
189 }
190 
191 
192 template<qx::unit_enum_c unit_t, class char_t>
193 constexpr std::optional<qx::basic_string_view<char_t>> qx::get_unit_suffix(unit_t eUnit) noexcept
194 {
195  const auto& suffixes = units::traits<unit_t>::template get_suffixes<char_t>();
196  auto itSuffix = std::ranges::find_if(
197  suffixes,
198  [eUnit](const std::pair<unit_t, basic_string_view<char_t>>& pair)
199  {
200  return pair.first == eUnit;
201  });
202  if (itSuffix != suffixes.end())
203  return itSuffix->second;
204  else
205  return std::nullopt;
206 }
207 
208 template<qx::arithmetic_c T, qx::unit_enum_c unit_t, class char_t>
209 template<class format_parse_context_t>
210 constexpr auto QX_FMT_NS::formatter<qx::unit<T, unit_t>, char_t>::parse(format_parse_context_t& context) noexcept
211 {
212  return m_ValueFormatter.parse(context);
213 }
214 
215 
216 template<qx::arithmetic_c T, qx::unit_enum_c unit_t, class char_t>
217 template<class format_context_type_t>
218 constexpr auto QX_FMT_NS::formatter<qx::unit<T, unit_t>, char_t>::format(
219  const qx::unit<T, unit_t>& unit,
220  format_context_type_t& ctx) const noexcept -> decltype(ctx.out())
221 {
222  auto outIt = m_ValueFormatter.format(unit.value, ctx);
223  return QX_FMT_NS::format_to(outIt, QX_STR_PREFIX(char_t, "{}"), unit.type);
224 }
225 
226 template<qx::unit_enum_c unit_t, class char_t>
227 template<class format_context_type_t>
228 constexpr auto qx::units::details::unit_formatter<unit_t, char_t>::format(unit_t eUnit, format_context_type_t& ctx)
229  const noexcept -> decltype(ctx.out())
230 {
231  auto out = ctx.out();
232 
233  if (std::optional<basic_string_view<char_t>> optSuffix = get_unit_suffix<unit_t, char_t>(eUnit))
234  out = QX_FMT_NS::format_to(out, QX_STR_PREFIX(char_t, "{}"), *optSuffix);
235 
236  return out;
237 }
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:120
Definition: base.h:52