Physical Quantities  v1.0.0
C++ library of physical quantities, physical models, and units of measure for scientific computing. https://github.com/acodcha/phq
Base.hpp
Go to the documentation of this file.
1 // Copyright © 2020-2024 Alexandre Coderre-Chabot
2 //
3 // This file is part of Physical Quantities (PhQ), a C++ library of physical quantities, physical
4 // models, and units of measure for scientific computing.
5 //
6 // Physical Quantities is hosted at:
7 // https://github.com/acodcha/phq
8 //
9 // Physical Quantities is licensed under the MIT License:
10 // https://mit-license.org
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
13 // associated documentation files (the "Software"), to deal in the Software without restriction,
14 // including without limitation the rights to use, copy, modify, merge, publish, distribute,
15 // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 // - The above copyright notice and this permission notice shall be included in all copies or
18 // substantial portions of the Software.
19 // - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
20 // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 #ifndef PHQ_BASE_HPP
26 #define PHQ_BASE_HPP
27 
28 #include <algorithm>
29 #include <climits>
30 #include <cmath>
31 #include <cstddef>
32 #include <cstdint>
33 #include <iomanip>
34 #include <iterator>
35 #include <limits>
36 #include <map>
37 #include <optional>
38 #include <sstream>
39 #include <string>
40 #include <string_view>
41 #include <type_traits>
42 #include <unordered_map>
43 #include <utility>
44 #include <vector>
45 
46 /// \brief Namespace that encompasses all of the Physical Quantities library's content.
47 namespace PhQ {
48 
49 /// \brief The mathematical constant π = 3.14...
50 /// \tparam NumericType Floating-point numeric type: float, double, or long double. Defaults to
51 /// double if unspecified.
52 template <typename NumericType = double>
53 inline constexpr NumericType Pi;
54 
55 /// \brief The mathematical constant π = 3.14... expressed as a single-precision 32-bit binary
56 /// floating-point number.
57 template <>
58 inline constexpr float Pi<float>{3.1415927F};
59 
60 /// \brief The mathematical constant π = 3.14... expressed as a double-precision 64-bit binary
61 /// floating-point number.
62 template <>
63 inline constexpr double Pi<double>{3.14159265358979323846};
64 
65 /// \brief The mathematical constant π = 3.14... expressed as an extended-precision binary
66 /// floating-point number. The exact implementation of the extended-precision type varies; the most
67 /// common implementations are 64-bit, 80-bit, 96-bit, or 128-bit binary floating-point numbers.
68 template <>
69 inline constexpr const long double Pi<long double>{3.141592653589793238462643383279502884L};
70 
71 /// @brief Namespace that contains base physical dimensions.
72 namespace Dimension {}
73 
74 /// \brief Namespace that contains internal implementation details of the Physical Quantities
75 /// library. Contents within this namespace are not meant to be used except by the the Physical
76 /// Quantities library's own functions and classes.
77 namespace Internal {
78 
79 /// \brief Map of enumerations to their corresponding abbreviations. This is an internal
80 /// implementation detail and is not intended to be used except by the PhQ::Abbreviation function.
81 template <typename Enumeration>
82 inline const std::map<Enumeration, std::string_view> Abbreviations;
83 
84 } // namespace Internal
85 
86 /// \brief Returns the abbreviation of a given enumeration value. For example,
87 /// PhQ::Abbreviation(PhQ::Unit::Time::Hour) returns "hr".
88 template <typename Enumeration>
89 [[nodiscard]] inline std::string_view Abbreviation(const Enumeration enumeration) {
90  return Internal::Abbreviations<Enumeration>.find(enumeration)->second;
91 }
92 
93 namespace Internal {
94 
95 /// \brief Map of spellings to their corresponding enumeration values. This is an internal
96 /// implementation detail and is not intended to be used except by the PhQ::ParseEnumeration
97 /// function.
98 template <typename Enumeration>
99 inline const std::unordered_map<std::string_view, Enumeration> Spellings;
100 
101 } // namespace Internal
102 
103 /// \brief Attempts to parse the given string as an enumeration of the given type. Returns a
104 /// std::optional container that contains the resulting enumeration if successful, or std::nullopt
105 /// if the given string could not be parsed into an enumeration of the given type.
106 template <typename Enumeration>
107 [[nodiscard]] std::optional<Enumeration> ParseEnumeration(const std::string_view spelling) {
108  const typename std::unordered_map<std::string_view, Enumeration>::const_iterator found{
109  Internal::Spellings<Enumeration>.find(spelling)};
110  if (found != Internal::Spellings<Enumeration>.cend()) {
111  return found->second;
112  }
113  return std::nullopt;
114 }
115 
116 /// \brief Parses the given string as a number of the given numeric type. Returns a std::optional
117 /// container that contains the resulting number if successful, or std::nullopt if the string could
118 /// not be parsed into the given numeric type.
119 /// \tparam NumericType Floating-point numeric type: float, double, or long double. Defaults to
120 /// double if unspecified.
121 template <typename NumericType = double>
122 [[nodiscard]] inline std::optional<NumericType> ParseNumber(const std::string& string);
123 
124 /// \brief Parses the given string as a single-precision floating-point number (a float). Returns a
125 /// std::optional container that contains the resulting number if successful, or std::nullopt if the
126 /// string could not be parsed into a float.
127 template <>
128 [[nodiscard]] inline std::optional<float> ParseNumber(const std::string& string) {
129  float number;
130  try {
131  number = std::stof(string);
132  } catch (...) {
133  return std::nullopt;
134  }
135  return number;
136 }
137 
138 /// \brief Parses the given string as a double-precision floating-point number (a double). Returns a
139 /// std::optional container that contains the resulting number if successful, or std::nullopt if the
140 /// string could not be parsed into a double.
141 template <>
142 [[nodiscard]] inline std::optional<double> ParseNumber(const std::string& string) {
143  double number;
144  try {
145  number = std::stod(string);
146  } catch (...) {
147  return std::nullopt;
148  }
149  return number;
150 }
151 
152 /// \brief Parses the given string as an extended-precision floating-point number (a long double).
153 /// Returns a std::optional container that contains the resulting number if successful, or
154 /// std::nullopt if the string could not be parsed into a long double.
155 template <>
156 [[nodiscard]] inline std::optional<long double> ParseNumber(const std::string& string) {
157  long double number;
158  try {
159  number = std::stold(string);
160  } catch (...) {
161  return std::nullopt;
162  }
163  return number;
164 }
165 
166 /// \brief Prints a given floating-point number as a string. Prints enough digits to represent the
167 /// number exactly. The printed number of digits depends on the type of the floating-point number.
168 /// \tparam NumericType Floating-point numeric type of the given value. Deduced automatically.
169 template <typename NumericType>
170 [[nodiscard]] inline std::string Print(const NumericType value) {
171  static_assert(std::is_floating_point<NumericType>::value,
172  "The NumericType template parameter of PhQ::Print<NumericType> must be a numeric "
173  "floating-point type: float, double, or long double.");
174  const NumericType absolute{std::abs(value)};
175  std::ostringstream stream;
176  if (absolute < 1.0) {
177  // Interval: [0, 1[
178  if (absolute < 0.001) {
179  // Interval: [0, 0.001[
180  if (absolute == 0.0) {
181  // Interval: [0, 0]
182  stream << 0;
183  } else {
184  // Interval: ]0, 0.001[
185  stream << std::scientific
186  << std::setprecision(std::numeric_limits<NumericType>::max_digits10) << value;
187  }
188  } else {
189  // Interval: [0.001, 1[
190  if (absolute < 0.1) {
191  // Interval: [0.001, 0.1[
192  if (absolute < 0.01) {
193  // Interval: [0.001, 0.01[
194  stream << std::fixed
195  << std::setprecision(std::numeric_limits<NumericType>::max_digits10 + 3) << value;
196  } else {
197  // Interval: [0.01, 0.1[
198  stream << std::fixed
199  << std::setprecision(std::numeric_limits<NumericType>::max_digits10 + 2) << value;
200  }
201  } else {
202  // Interval: [0.1, 1[
203  stream << std::fixed
204  << std::setprecision(std::numeric_limits<NumericType>::max_digits10 + 1) << value;
205  }
206  }
207  } else {
208  // Interval: [1, +inf[
209  if (absolute < 1000.0) {
210  // Interval: [1, 1000[
211  if (absolute < 10.0) {
212  // Interval: [1, 10[
213  stream << std::fixed << std::setprecision(std::numeric_limits<NumericType>::max_digits10)
214  << value;
215  } else {
216  // Interval: [10, 1000[
217  if (absolute < 100.0) {
218  // Interval: [10, 100[
219  stream << std::fixed
220  << std::setprecision(std::numeric_limits<NumericType>::max_digits10 - 1) << value;
221  } else {
222  // Interval: [100, 1000[
223  stream << std::fixed
224  << std::setprecision(std::numeric_limits<NumericType>::max_digits10 - 2) << value;
225  }
226  }
227  } else {
228  // Interval: [1000, +inf[
229  if (absolute < 10000.0) {
230  // Interval: [1000, 10000[
231  stream << std::fixed
232  << std::setprecision(std::numeric_limits<NumericType>::max_digits10 - 3) << value;
233  } else {
234  // Interval: [10000, +inf[
235  stream << std::scientific
236  << std::setprecision(std::numeric_limits<NumericType>::max_digits10) << value;
237  }
238  }
239  }
240  return stream.str();
241 }
242 
243 /// \brief Returns a copy of the given string where all characters are lowercase.
244 [[nodiscard]] inline std::string Lowercase(const std::string_view string) {
245  std::string result{string};
246  std::transform(result.begin(), result.end(), result.begin(), [](int character) {
247  return std::tolower(character);
248  });
249  return result;
250 }
251 
252 /// \brief Returns a copy of the given string where all characters are uppercase.
253 [[nodiscard]] inline std::string Uppercase(const std::string_view string) {
254  std::string result{string};
255  std::transform(result.begin(), result.end(), result.begin(), [](int character) {
256  return std::toupper(character);
257  });
258  return result;
259 }
260 
261 /// \brief Returns a copy of the given string in snake case: all characters are lowercase and all
262 /// spaces are replaced with underscores.
263 [[nodiscard]] inline std::string SnakeCase(const std::string_view string) {
264  std::string result{Lowercase(string)};
265  std::replace(result.begin(), result.end(), ' ', '_');
266  return result;
267 }
268 
269 } // namespace PhQ
270 
271 #endif // PHQ_BASE_HPP
Namespace that encompasses all of the Physical Quantities library's content.
constexpr NumericType Pi
The mathematical constant π = 3.14...
Definition: Base.hpp:53
std::optional< NumericType > ParseNumber(const std::string &string)
Parses the given string as a number of the given numeric type. Returns a std::optional container that...
Definition: Base.hpp:128
std::string Lowercase(const std::string_view string)
Returns a copy of the given string where all characters are lowercase.
Definition: Base.hpp:244
constexpr double Pi< double >
The mathematical constant π = 3.14... expressed as a double-precision 64-bit binary floating-point nu...
Definition: Base.hpp:63
std::string SnakeCase(const std::string_view string)
Returns a copy of the given string in snake case: all characters are lowercase and all spaces are rep...
Definition: Base.hpp:263
std::string_view Abbreviation(const Enumeration enumeration)
Returns the abbreviation of a given enumeration value. For example, PhQ::Abbreviation(PhQ::Unit::Time...
Definition: Base.hpp:89
std::string Uppercase(const std::string_view string)
Returns a copy of the given string where all characters are uppercase.
Definition: Base.hpp:253
constexpr float Pi< float >
The mathematical constant π = 3.14... expressed as a single-precision 32-bit binary floating-point nu...
Definition: Base.hpp:58
std::optional< Enumeration > ParseEnumeration(const std::string_view spelling)
Attempts to parse the given string as an enumeration of the given type. Returns a std::optional conta...
Definition: Base.hpp:107
constexpr const long double Pi< long double >
The mathematical constant π = 3.14... expressed as an extended-precision binary floating-point number...
Definition: Base.hpp:69
std::string Print(const NumericType value)
Prints a given floating-point number as a string. Prints enough digits to represent the number exactl...
Definition: Base.hpp:170