Physical Quantities  v1.0.0
C++ library of physical quantities, physical models, and units of measure for scientific computing. https://github.com/acodcha/phq
Loading...
Searching...
No Matches
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.
47namespace 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.
52template <typename NumericType = double>
53inline constexpr NumericType Pi;
54
55/// \brief The mathematical constant π = 3.14... expressed as a single-precision 32-bit binary
56/// floating-point number.
57template <>
58inline 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.
62template <>
63inline 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.
68template <>
69inline constexpr const long double Pi<long double>{3.141592653589793238462643383279502884L};
70
71/// @brief Namespace that contains base physical dimensions.
72namespace 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.
77namespace 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.
81template <typename Enumeration>
82inline 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".
88template <typename Enumeration>
89[[nodiscard]] inline std::string_view Abbreviation(const Enumeration enumeration) {
90 return Internal::Abbreviations<Enumeration>.find(enumeration)->second;
91}
92
93namespace 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.
98template <typename Enumeration>
99inline 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.
106template <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.
121template <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.
127template <>
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.
141template <>
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.
155template <>
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.
169template <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< 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
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...
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
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