Lector v1.0.0
C++ library for parsing command line arguments.
parse.hpp
1// Copyright © 2026, Alexandre Coderre-Chabot.
2
3// This file is part of Lector (https://github.com/acodcha/lector), a C++ library for parsing
4// command line arguments. Lector is licensed under the MIT License (https://mit-license.org).
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
7// associated documentation files (the "Software"), to deal in the Software without restriction,
8// including without limitation the rights to use, copy, modify, merge, publish, distribute,
9// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11// - The above copyright notice and this permission notice shall be included in all copies or
12// substantial portions of the Software.
13// - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
14// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
16// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM
17// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
19#ifndef LECTOR_PARSE_HPP
20#define LECTOR_PARSE_HPP
21
22#include <algorithm>
23#include <array>
24#include <charconv>
25#include <cstdint>
26#include <filesystem>
27#include <limits>
28#include <optional>
29#include <sstream>
30#include <string>
31#include <string_view>
32#include <system_error>
33#include <type_traits>
34
35#ifdef __APPLE__
36 #include <cstddef>
37#endif // __APPLE__
38
39/// @brief The Lector library's namespace.
40namespace lector {
41
42/// @brief A possible spelling for a value of a specified type.
43/// @tparam Type The type of the value.
44template <typename Type>
45using Spelling = ::std::pair<::std::string_view, Type>;
46
47/// \brief Map of spellings to their corresponding values of a specified type.
48/// @tparam Type The type of the values.
49template <typename Type>
50inline constexpr ::std::array<::lector::Spelling<Type>, 0UL> Spellings{};
51
52/// @brief Parses a string of text into an enumeration value. The enumeration type must define a
53/// specialization of the lector::Spellings constant for its type.
54/// @tparam EnumerationType The enumeration type.
55/// @param[in] text The string of text to parse.
56/// @return The parsed enumeration value, or std::nullopt if the string of text could not be parsed
57/// into a valid enumeration value.
58template <typename EnumerationType>
59[[nodiscard]] constexpr ::std::optional<EnumerationType> parse_enumeration(
60 const ::std::string_view text) {
61 static_assert(std::is_enum_v<EnumerationType>);
62 for (const auto& [spelling, value] : ::lector::Spellings<EnumerationType>) {
63 if (spelling == text) {
64 return value;
65 }
66 }
67 return ::std::nullopt;
68}
69
70/// @brief Parses a string of text into a value of a specific type. If the type is an enumeration
71/// type, it must define a specialization of the lector::Spellings constant for its type.
72/// @tparam Type The type of the value in which to parse the string of text.
73/// @param[in] text The string of text to parse.
74/// @return The parsed value, or std::nullopt if the string of text could not be parsed into a valid
75/// value.
76template <typename Type>
77[[nodiscard]] ::std::optional<Type> parse(::std::string_view text);
78
79/// @brief Parses a string of text into a boolean value. For example, the string of text "true"
80/// returns the boolean value true.
81/// @param[in] text The string of text to parse.
82/// @return The parsed boolean value, or std::nullopt if the string of text could not be parsed into
83/// a valid boolean value.
84template <>
85[[nodiscard]] inline ::std::optional<bool> parse(const ::std::string_view text) {
86 if (text == "true" || text == "True" || text == "TRUE") {
87 return true;
88 }
89 if (text == "false" || text == "False" || text == "FALSE") {
90 return false;
91 }
92 return ::std::nullopt;
93}
94
95/// @brief Parses a string of text into an 8-bit natural number. For example, the string of text
96/// "42" returns the number 42.
97/// @param[in] text The string of text to parse.
98/// @return The parsed 8-bit natural number, or std::nullopt if the string of text could not be
99/// parsed into a valid 8-bit natural number.
100template <>
101[[nodiscard]] inline ::std::optional<::std::uint8_t> parse(const ::std::string_view text) {
102 ::std::string_view modified_text{text};
103 // Strip leading and trailing whitespace.
104 modified_text.remove_prefix(
105 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
106 modified_text.remove_suffix(
107 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
108 if (modified_text.empty()) {
109 return ::std::nullopt;
110 }
111 // Strip the leading '+' or '-' sign, if any, and make note of the sign.
112 bool is_negative{false};
113 if (modified_text.front() == '-') {
114 is_negative = true;
115 modified_text.remove_prefix(1);
116 } else if (modified_text.front() == '+') {
117 modified_text.remove_prefix(1);
118 }
119 // Parse the text into a number using std::from_chars().
120 ::std::uint8_t number{0U};
121 const ::std::from_chars_result result{
122 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
123 if (result.ec != ::std::errc{}) {
124 return ::std::nullopt;
125 }
126 if (result.ptr != modified_text.data() + modified_text.size()) {
127 return ::std::nullopt;
128 }
129 // The only allowed negative number is -0, which parses to 0.
130 if (is_negative && number != 0U) {
131 return ::std::nullopt;
132 }
133 return number;
134}
135
136/// @brief Parses a string of text into a 16-bit natural number. For example, the string of text
137/// "42" returns the number 42.
138/// @param[in] text The string of text to parse.
139/// @return The parsed 16-bit natural number, or std::nullopt if the string of text could not be
140/// parsed into a valid 16-bit natural number.
141template <>
142[[nodiscard]] inline ::std::optional<::std::uint16_t> parse(const ::std::string_view text) {
143 ::std::string_view modified_text{text};
144 // Strip leading and trailing whitespace.
145 modified_text.remove_prefix(
146 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
147 modified_text.remove_suffix(
148 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
149 if (modified_text.empty()) {
150 return ::std::nullopt;
151 }
152 // Strip the leading '+' or '-' sign, if any, and make note of the sign.
153 bool is_negative{false};
154 if (modified_text.front() == '-') {
155 is_negative = true;
156 modified_text.remove_prefix(1);
157 } else if (modified_text.front() == '+') {
158 modified_text.remove_prefix(1);
159 }
160 // Parse the text into a number using std::from_chars().
161 ::std::uint16_t number{0U};
162 const ::std::from_chars_result result{
163 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
164 if (result.ec != ::std::errc{}) {
165 return ::std::nullopt;
166 }
167 if (result.ptr != modified_text.data() + modified_text.size()) {
168 return ::std::nullopt;
169 }
170 // The only allowed negative number is -0, which parses to 0.
171 if (is_negative && number != 0U) {
172 return ::std::nullopt;
173 }
174 return number;
175}
176
177/// @brief Parses a string of text into a 32-bit natural number. For example, the string of text
178/// "42" returns the number 42.
179/// @param[in] text The string of text to parse.
180/// @return The parsed 32-bit natural number, or std::nullopt if the string of text could not be
181/// parsed into a valid 32-bit natural number.
182template <>
183[[nodiscard]] inline ::std::optional<::std::uint32_t> parse(const ::std::string_view text) {
184 ::std::string_view modified_text{text};
185 // Strip leading and trailing whitespace.
186 modified_text.remove_prefix(
187 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
188 modified_text.remove_suffix(
189 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
190 if (modified_text.empty()) {
191 return ::std::nullopt;
192 }
193 // Strip the leading '+' or '-' sign, if any, and make note of the sign.
194 bool is_negative{false};
195 if (modified_text.front() == '-') {
196 is_negative = true;
197 modified_text.remove_prefix(1);
198 } else if (modified_text.front() == '+') {
199 modified_text.remove_prefix(1);
200 }
201 // Parse the text into a number using std::from_chars().
202 ::std::uint32_t number{0U};
203 const ::std::from_chars_result result{
204 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
205 if (result.ec != ::std::errc{}) {
206 return ::std::nullopt;
207 }
208 if (result.ptr != modified_text.data() + modified_text.size()) {
209 return ::std::nullopt;
210 }
211 // The only allowed negative number is -0, which parses to 0.
212 if (is_negative && number != 0U) {
213 return ::std::nullopt;
214 }
215 return number;
216}
217
218/// @brief Parses a string of text into a 64-bit natural number. For example, the string of text
219/// "42" returns the number 42.
220/// @param[in] text The string of text to parse.
221/// @return The parsed 64-bit natural number, or std::nullopt if the string of text could not be
222/// parsed into a valid 64-bit natural number.
223template <>
224[[nodiscard]] inline ::std::optional<::std::uint64_t> parse(const ::std::string_view text) {
225 ::std::string_view modified_text{text};
226 // Strip leading and trailing whitespace.
227 modified_text.remove_prefix(
228 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
229 modified_text.remove_suffix(
230 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
231 if (modified_text.empty()) {
232 return ::std::nullopt;
233 }
234 // Strip the leading '+' or '-' sign, if any, and make note of the sign.
235 bool is_negative{false};
236 if (modified_text.front() == '-') {
237 is_negative = true;
238 modified_text.remove_prefix(1);
239 } else if (modified_text.front() == '+') {
240 modified_text.remove_prefix(1);
241 }
242 // Parse the text into a number using std::from_chars().
243 ::std::uint64_t number{0UL};
244 const ::std::from_chars_result result{
245 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
246 if (result.ec != ::std::errc{}) {
247 return ::std::nullopt;
248 }
249 if (result.ptr != modified_text.data() + modified_text.size()) {
250 return ::std::nullopt;
251 }
252 // The only allowed negative number is -0, which parses to 0.
253 if (is_negative && number != 0UL) {
254 return ::std::nullopt;
255 }
256 return number;
257}
258
259/// @brief Parses a string of text into an 8-bit integer number. For example, the string of text
260/// "42" returns the number 42.
261/// @param[in] text The string of text to parse.
262/// @return The parsed 8-bit integer number, or std::nullopt if the string of text could not be
263/// parsed into a valid 8-bit integer number.
264template <>
265[[nodiscard]] inline ::std::optional<::std::int8_t> parse(const ::std::string_view text) {
266 ::std::string_view modified_text{text};
267 // Strip leading and trailing whitespace.
268 modified_text.remove_prefix(
269 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
270 modified_text.remove_suffix(
271 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
272 if (modified_text.empty()) {
273 return ::std::nullopt;
274 }
275 // Strip the leading '+' sign, if any.
276 if (modified_text.front() == '+') {
277 modified_text.remove_prefix(1);
278 }
279 // Parse the text into a number using std::from_chars().
280 ::std::int8_t number{0};
281 const ::std::from_chars_result result{
282 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
283 if (result.ec != ::std::errc{}) {
284 return ::std::nullopt;
285 }
286 if (result.ptr != modified_text.data() + modified_text.size()) {
287 return ::std::nullopt;
288 }
289 return number;
290}
291
292/// @brief Parses a string of text into a 16-bit integer number. For example, the string of text
293/// "42" returns the number 42.
294/// @param[in] text The string of text to parse.
295/// @return The parsed 16-bit integer number, or std::nullopt if the string of text could not be
296/// parsed into a valid 16-bit integer number.
297template <>
298[[nodiscard]] inline ::std::optional<::std::int16_t> parse(const ::std::string_view text) {
299 ::std::string_view modified_text{text};
300 // Strip leading and trailing whitespace.
301 modified_text.remove_prefix(
302 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
303 modified_text.remove_suffix(
304 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
305 if (modified_text.empty()) {
306 return ::std::nullopt;
307 }
308 // Strip the leading '+' sign, if any.
309 if (modified_text.front() == '+') {
310 modified_text.remove_prefix(1);
311 }
312 // Parse the text into a number using std::from_chars().
313 ::std::int16_t number{0};
314 const ::std::from_chars_result result{
315 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
316 if (result.ec != ::std::errc{}) {
317 return ::std::nullopt;
318 }
319 if (result.ptr != modified_text.data() + modified_text.size()) {
320 return ::std::nullopt;
321 }
322 return number;
323}
324
325/// @brief Parses a string of text into a 32-bit integer number. For example, the string of text
326/// "42" returns the number 42.
327/// @param[in] text The string of text to parse.
328/// @return The parsed 32-bit integer number, or std::nullopt if the string of text could not be
329/// parsed into a valid 32-bit integer number.
330template <>
331[[nodiscard]] inline ::std::optional<::std::int32_t> parse(const ::std::string_view text) {
332 ::std::string_view modified_text{text};
333 // Strip leading and trailing whitespace.
334 modified_text.remove_prefix(
335 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
336 modified_text.remove_suffix(
337 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
338 if (modified_text.empty()) {
339 return ::std::nullopt;
340 }
341 // Strip the leading '+' sign, if any.
342 if (modified_text.front() == '+') {
343 modified_text.remove_prefix(1);
344 }
345 // Parse the text into a number using std::from_chars().
346 ::std::int32_t number{0};
347 const ::std::from_chars_result result{
348 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
349 if (result.ec != ::std::errc{}) {
350 return ::std::nullopt;
351 }
352 if (result.ptr != modified_text.data() + modified_text.size()) {
353 return ::std::nullopt;
354 }
355 return number;
356}
357
358/// @brief Parses a string of text into a 64-bit integer number. For example, the string of text
359/// "42" returns the number 42.
360/// @param[in] text The string of text to parse.
361/// @return The parsed 64-bit integer number, or std::nullopt if the string of text could not be
362/// parsed into a valid 64-bit integer number.
363template <>
364[[nodiscard]] inline ::std::optional<::std::int64_t> parse(const ::std::string_view text) {
365 ::std::string_view modified_text{text};
366 // Strip leading and trailing whitespace.
367 modified_text.remove_prefix(
368 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
369 modified_text.remove_suffix(
370 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
371 if (modified_text.empty()) {
372 return ::std::nullopt;
373 }
374 // Strip the leading '+' sign, if any.
375 if (modified_text.front() == '+') {
376 modified_text.remove_prefix(1);
377 }
378 // Parse the text into a number using std::from_chars().
379 ::std::int64_t number{0L};
380 const ::std::from_chars_result result{
381 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
382 if (result.ec != ::std::errc{}) {
383 return ::std::nullopt;
384 }
385 if (result.ptr != modified_text.data() + modified_text.size()) {
386 return ::std::nullopt;
387 }
388 return number;
389}
390
391/// @brief Parses a string of text into a single-precision floating-point number. For example, the
392/// string of text "3.14" returns the number 3.14.
393/// @param[in] text The string of text to parse.
394/// @return The parsed single-precision floating-point number, or std::nullopt if the string of text
395/// could not be parsed into a valid single-precision floating-point number.
396template <>
397[[nodiscard]] inline ::std::optional<float> parse(const ::std::string_view text) {
398 ::std::string_view modified_text{text};
399 // Strip leading and trailing whitespace.
400 modified_text.remove_prefix(
401 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
402 modified_text.remove_suffix(
403 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
404 if (modified_text.empty()) {
405 return ::std::nullopt;
406 }
407 // Strip the leading '+' sign, if any.
408 if (modified_text.front() == '+') {
409 modified_text.remove_prefix(1);
410 }
411#ifdef __APPLE__
412 // Check if the first character is a '+' sign. This is needed because std::stod() accepts "++1.0".
413 if (!modified_text.empty() && modified_text.front() == '+') {
414 return ::std::nullopt;
415 }
416 // Parse the text into a number using std::stof() instead of std::from_chars(). The <charconv>
417 // library on macOS has an older version of std::from_chars() that only supports integral types
418 // and does not support floating-point types.
419 float number{0.0F};
420 ::std::size_t position{0UL};
421 try {
422 const ::std::string modified_text_string{modified_text};
423 number = ::std::stof(modified_text_string, &position);
424 if (position != modified_text_string.size()) {
425 return ::std::nullopt;
426 }
427 } catch (...) {
428 return ::std::nullopt;
429 }
430 return number;
431#else
432 // Parse the text into a number using std::from_chars().
433 float number{0.0F};
434 const ::std::from_chars_result result{
435 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
436 if (result.ec != ::std::errc{}) {
437 return ::std::nullopt;
438 }
439 if (result.ptr != modified_text.data() + modified_text.size()) {
440 return ::std::nullopt;
441 }
442 return number;
443#endif // __APPLE__
444}
445
446/// @brief Parses a string of text into a double-precision floating-point number. For example, the
447/// string of text "3.14" returns the number 3.14.
448/// @param[in] text The string of text to parse.
449/// @return The parsed double-precision floating-point number, or std::nullopt if the string of text
450/// could not be parsed into a valid double-precision floating-point number.
451template <>
452[[nodiscard]] inline ::std::optional<double> parse(const ::std::string_view text) {
453 ::std::string_view modified_text{text};
454 // Strip leading and trailing whitespace.
455 modified_text.remove_prefix(
456 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
457 modified_text.remove_suffix(
458 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
459 if (modified_text.empty()) {
460 return ::std::nullopt;
461 }
462 // Strip the leading '+' sign, if any.
463 if (modified_text.front() == '+') {
464 modified_text.remove_prefix(1);
465 }
466#ifdef __APPLE__
467 // Check if the first character is a '+' sign. This is needed because std::stod() accepts "++1.0".
468 if (!modified_text.empty() && modified_text.front() == '+') {
469 return ::std::nullopt;
470 }
471 // Parse the text into a number using std::stod() instead of std::from_chars(). The <charconv>
472 // library on macOS has an older version of std::from_chars() that only supports integral types
473 // and does not support floating-point types.
474 double number{0.0};
475 ::std::size_t position{0UL};
476 try {
477 const ::std::string modified_text_string{modified_text};
478 number = ::std::stod(modified_text_string, &position);
479 if (position != modified_text_string.size()) {
480 return ::std::nullopt;
481 }
482 } catch (...) {
483 return ::std::nullopt;
484 }
485 return number;
486#else
487 // Parse the text into a number using std::from_chars().
488 double number{0.0};
489 const ::std::from_chars_result result{
490 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
491 if (result.ec != ::std::errc{}) {
492 return ::std::nullopt;
493 }
494 if (result.ptr != modified_text.data() + modified_text.size()) {
495 return ::std::nullopt;
496 }
497 return number;
498#endif // __APPLE__
499}
500
501/// @brief Parses a string of text into an extended-precision floating-point number. For example,
502/// the string of text "3.14" returns the number 3.14.
503/// @param[in] text The string of text to parse.
504/// @return The parsed extended-precision floating-point number, or std::nullopt if the string of
505/// text could not be parsed into a valid extended-precision floating-point number.
506template <>
507[[nodiscard]] inline ::std::optional<long double> parse(const ::std::string_view text) {
508 ::std::string_view modified_text{text};
509 // Strip leading and trailing whitespace.
510 modified_text.remove_prefix(
511 ::std::min(modified_text.find_first_not_of(" \t\r\n"), modified_text.size()));
512 modified_text.remove_suffix(
513 modified_text.size() - (modified_text.find_last_not_of(" \t\r\n") + 1));
514 if (modified_text.empty()) {
515 return ::std::nullopt;
516 }
517 // Strip the leading '+' sign, if any.
518 if (modified_text.front() == '+') {
519 modified_text.remove_prefix(1);
520 }
521#ifdef __APPLE__
522 // Check if the first character is a '+' sign. This is needed because std::stod() accepts "++1.0".
523 if (!modified_text.empty() && modified_text.front() == '+') {
524 return ::std::nullopt;
525 }
526 // Parse the text into a number using std::stod() instead of std::from_chars(). The <charconv>
527 // library on macOS has an older version of std::from_chars() that only supports integral types
528 // and does not support floating-point types.
529 long double number{0.0L};
530 ::std::size_t position{0UL};
531 try {
532 const ::std::string modified_text_string{modified_text};
533 number = ::std::stold(modified_text_string, &position);
534 if (position != modified_text_string.size()) {
535 return ::std::nullopt;
536 }
537 } catch (...) {
538 return ::std::nullopt;
539 }
540 return number;
541#else
542 // Parse the text into a number using std::from_chars().
543 long double number{0.0L};
544 const ::std::from_chars_result result{
545 ::std::from_chars(modified_text.data(), modified_text.data() + modified_text.size(), number)};
546 if (result.ec != ::std::errc{}) {
547 return ::std::nullopt;
548 }
549 if (result.ptr != modified_text.data() + modified_text.size()) {
550 return ::std::nullopt;
551 }
552 return number;
553#endif // __APPLE__
554}
555
556/// @brief Parses a string view into a string of text.
557/// @param[in] text The string view to parse.
558/// @return The parsed string.
559template <>
560[[nodiscard]] inline ::std::optional<::std::string> parse(const ::std::string_view text) {
561 return ::std::string{text};
562}
563
564/// @brief Returns a string of text as-is.
565/// @param[in] text The string of text.
566/// @return The string of text.
567template <>
568[[nodiscard]] inline ::std::optional<::std::string_view> parse(const ::std::string_view text) {
569 return text;
570}
571
572/// @brief Parses a string of text into a filesystem path.
573/// @param[in] text The string of text to parse.
574/// @return The parsed filesystem path, or std::nullopt if the string of text could not be parsed
575/// into a valid filesystem path.
576template <>
577[[nodiscard]] inline ::std::optional<::std::filesystem::path> parse(const ::std::string_view text) {
578 return ::std::filesystem::path{text};
579}
580
581/// @brief Parses a string of text into a value of a specific type. If the type is an enumeration
582/// type, it must define a specialization of the lector::Spellings constant for its type; otherwise,
583/// the type must be streamable with the >> input stream operator.
584/// @tparam Type The type of the value in which to parse the string of text.
585/// @param[in] text The string of text to parse.
586/// @return The parsed value, or std::nullopt if the string of text could not be parsed into a valid
587/// value.
588template <typename Type>
589[[nodiscard]] inline ::std::optional<Type> parse(const ::std::string_view text) {
590 if constexpr (::std::is_enum_v<Type>) {
591 return ::lector::parse_enumeration<Type>(text);
592 } else {
593 ::std::istringstream stream{::std::string{text}};
594 Type value;
595 if (stream >> value) {
596 if (stream.eof()) {
597 return value;
598 }
599 }
600 return ::std::nullopt;
601 }
602}
603
604} // namespace lector
605
606#endif // LECTOR_PARSE_HPP
The Lector library's namespace.
Definition arguments.hpp:45
constexpr ::std::optional< EnumerationType > parse_enumeration(const ::std::string_view text)
Parses a string of text into an enumeration value. The enumeration type must define a specialization ...
Definition parse.hpp:59
::std::optional< Type > parse(::std::string_view text)
Parses a string of text into a value of a specific type. If the type is an enumeration type,...
Definition parse.hpp:589
::std::pair<::std::string_view, Type > Spelling
A possible spelling for a value of a specified type.
Definition parse.hpp:45
constexpr ::std::array<::lector::Spelling< Type >, 0UL > Spellings
Map of spellings to their corresponding values of a specified type.
Definition parse.hpp:50