Serenity Operating System
1/*
2 * Copyright (c) 2022, David Tuin <davidot@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#ifdef KERNEL
10# error This file should not be included in the KERNEL as it deals with doubles \
11 and there is no guraantee does not do any floating point computations.
12#endif
13
14#include <AK/StringView.h>
15
16namespace AK {
17
18static constexpr char floating_point_decimal_separator = '.';
19
20enum class FloatingPointError {
21 None,
22 NoOrInvalidInput,
23 OutOfRange,
24 RoundedDownToZero
25};
26
27template<FloatingPoint T>
28struct FloatingPointParseResults {
29 char const* end_ptr { nullptr };
30 FloatingPointError error = FloatingPointError::None;
31 T value {};
32
33 [[nodiscard]] bool parsed_value() const
34 {
35 // All other errors do indicate out of range but did produce a valid value.
36 return error != FloatingPointError::NoOrInvalidInput;
37 }
38};
39
40/// This function finds the first floating point within [start, end). The accepted format is
41/// intentionally as lenient as possible. If your format is stricter you must validate it
42/// first. The format accepts:
43/// - An optional sign, both + and - are supported
44/// - 0 or more decimal digits, with leading zeros allowed [1]
45/// - A decimal point '.', which can have no digits after it
46/// - 0 or more decimal digits, unless the first digits [1] doesn't have any digits,
47/// then this must have at least one
48/// - An exponent 'e' or 'E' followed by an optional sign '+' or '-' and at least one digit
49/// This function additionally detects out of range values which have been rounded to
50/// [-]infinity or 0 and gives the next character to read after the floating point.
51template<FloatingPoint T = double>
52FloatingPointParseResults<T> parse_first_floating_point(char const* start, char const* end);
53
54/// This function finds the first floating point starting at start up to the first '\0'.
55/// The format is identical to parse_first_floating_point above.
56template<FloatingPoint T = double>
57FloatingPointParseResults<T> parse_first_floating_point_until_zero_character(char const* start);
58
59/// This function will return either a floating point, or an empty optional if the given StringView
60/// does not a floating point or contains more characters beyond the floating point. For the format
61/// check the comment on parse_first_floating_point.
62template<FloatingPoint T = double>
63Optional<T> parse_floating_point_completely(char const* start, char const* end);
64
65/// This function finds the first floating point as a hex float within [start, end).
66/// The accepted format is intentionally as lenient as possible. If your format is
67/// stricter you must validate it first. The format accepts:
68/// - An optional sign, both + and - are supported
69/// - Optionally either 0x or OX
70/// - 0 or more hexadecimal digits, with leading zeros allowed [1]
71/// - A decimal point '.', which can have no digits after it
72/// - 0 or more hexadecimal digits, unless the first digits [1] doesn't have any digits,
73/// then this must have at least one
74/// - An exponent 'p' or 'P' followed by an optional sign '+' or '-' and at least one decimal digit
75/// NOTE: The exponent is _not_ hexadecimal and gives powers of 2 not 16.
76/// This function additionally detects out of range values which have been rounded to
77/// [-]infinity or 0 and gives the next character to read after the floating point.
78template<FloatingPoint T = double>
79FloatingPointParseResults<T> parse_first_hexfloat_until_zero_character(char const* start);
80
81}
82
83#if USING_AK_GLOBALLY
84using AK::parse_first_floating_point;
85using AK::parse_first_hexfloat_until_zero_character;
86using AK::parse_floating_point_completely;
87#endif