mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 01:07:44 +00:00
AK: Make string-to-number conversion helpers return Optional
Get rid of the weird old signature: - int StringType::to_int(bool& ok) const And replace it with sensible new signature: - Optional<int> StringType::to_int() const
This commit is contained in:
parent
15f4043a7a
commit
fdfda6dec2
55 changed files with 354 additions and 455 deletions
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringUtils.h>
|
||||
#include <AK/StringView.h>
|
||||
|
@ -88,9 +89,9 @@ FlyString::FlyString(const char* string)
|
|||
{
|
||||
}
|
||||
|
||||
int FlyString::to_int(bool& ok) const
|
||||
Optional<int> FlyString::to_int() const
|
||||
{
|
||||
return StringUtils::convert_to_int(view(), ok);
|
||||
return StringUtils::convert_to_int(view());
|
||||
}
|
||||
|
||||
bool FlyString::equals_ignoring_case(const StringView& other) const
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
|
||||
FlyString to_lowercase() const;
|
||||
|
||||
int to_int(bool& ok) const;
|
||||
Optional<int> to_int() const;
|
||||
|
||||
bool equals_ignoring_case(const StringView&) const;
|
||||
bool ends_with(const StringView&, CaseSensitivity = CaseSensitivity::CaseSensitive) const;
|
||||
|
|
|
@ -78,18 +78,11 @@ public:
|
|||
auto parts = string.split_view('.');
|
||||
if (parts.size() != 4)
|
||||
return {};
|
||||
bool ok;
|
||||
auto a = parts[0].to_uint(ok);
|
||||
if (!ok || a > 255)
|
||||
return {};
|
||||
auto b = parts[1].to_uint(ok);
|
||||
if (!ok || b > 255)
|
||||
return {};
|
||||
auto c = parts[2].to_uint(ok);
|
||||
if (!ok || c > 255)
|
||||
return {};
|
||||
auto d = parts[3].to_uint(ok);
|
||||
if (!ok || d > 255)
|
||||
auto a = parts[0].to_uint().value_or(256);
|
||||
auto b = parts[1].to_uint().value_or(256);
|
||||
auto c = parts[2].to_uint().value_or(256);
|
||||
auto d = parts[3].to_uint().value_or(256);
|
||||
if (a > 255 || b > 255 || c > 255 || d > 255)
|
||||
return {};
|
||||
return IPv4Address((u8)a, (u8)b, (u8)c, (u8)d);
|
||||
}
|
||||
|
|
|
@ -123,10 +123,9 @@ String JsonParser::consume_quoted_string()
|
|||
sb.append(consume());
|
||||
sb.append(consume());
|
||||
|
||||
bool ok;
|
||||
u32 codepoint = AK::StringUtils::convert_to_uint_from_hex(sb.to_string(), ok);
|
||||
if (ok && codepoint < 128) {
|
||||
buffer.append((char)codepoint);
|
||||
auto codepoint = AK::StringUtils::convert_to_uint_from_hex(sb.to_string());
|
||||
if (codepoint.has_value() && codepoint.value() < 0x80) {
|
||||
buffer.append((char)codepoint.value());
|
||||
} else {
|
||||
// FIXME: This is obviously not correct, but we don't have non-ASCII support so meh.
|
||||
buffer.append('?');
|
||||
|
@ -202,7 +201,6 @@ JsonValue JsonParser::parse_string()
|
|||
|
||||
JsonValue JsonParser::parse_number()
|
||||
{
|
||||
bool ok;
|
||||
JsonValue value;
|
||||
Vector<char, 128> number_buffer;
|
||||
Vector<char, 128> fraction_buffer;
|
||||
|
@ -231,14 +229,17 @@ JsonValue JsonParser::parse_number()
|
|||
|
||||
#ifndef KERNEL
|
||||
if (is_double) {
|
||||
int whole = number_string.to_uint(ok);
|
||||
if (!ok)
|
||||
whole = number_string.to_int(ok);
|
||||
ASSERT(ok);
|
||||
// FIXME: This logic looks shaky.
|
||||
int whole = 0;
|
||||
auto to_signed_result = number_string.to_uint();
|
||||
if (to_signed_result.has_value()) {
|
||||
whole = to_signed_result.value();
|
||||
} else {
|
||||
whole = number_string.to_int().value();
|
||||
}
|
||||
|
||||
int fraction = fraction_string.to_uint(ok);
|
||||
int fraction = fraction_string.to_uint().value();
|
||||
fraction *= (whole < 0) ? -1 : 1;
|
||||
ASSERT(ok);
|
||||
|
||||
auto divider = 1;
|
||||
for (size_t i = 0; i < fraction_buffer.size(); ++i) {
|
||||
|
@ -247,10 +248,12 @@ JsonValue JsonParser::parse_number()
|
|||
value = JsonValue((double)whole + ((double)fraction / divider));
|
||||
} else {
|
||||
#endif
|
||||
value = JsonValue(number_string.to_uint(ok));
|
||||
if (!ok)
|
||||
value = JsonValue(number_string.to_int(ok));
|
||||
ASSERT(ok);
|
||||
auto to_unsigned_result = number_string.to_uint();
|
||||
if (to_unsigned_result.has_value()) {
|
||||
value = JsonValue(to_unsigned_result.value());
|
||||
} else {
|
||||
value = JsonValue(number_string.to_int().value());
|
||||
}
|
||||
#ifndef KERNEL
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -196,14 +196,14 @@ ByteBuffer String::to_byte_buffer() const
|
|||
return ByteBuffer::copy(reinterpret_cast<const u8*>(characters()), length());
|
||||
}
|
||||
|
||||
int String::to_int(bool& ok) const
|
||||
Optional<int> String::to_int() const
|
||||
{
|
||||
return StringUtils::convert_to_int(this->view(), ok);
|
||||
return StringUtils::convert_to_int(view());
|
||||
}
|
||||
|
||||
unsigned String::to_uint(bool& ok) const
|
||||
Optional<unsigned> String::to_uint() const
|
||||
{
|
||||
return StringUtils::convert_to_uint(this->view(), ok);
|
||||
return StringUtils::convert_to_uint(view());
|
||||
}
|
||||
|
||||
String String::number(unsigned long long value)
|
||||
|
|
|
@ -108,8 +108,8 @@ public:
|
|||
static String repeated(char, size_t count);
|
||||
bool matches(const StringView& mask, CaseSensitivity = CaseSensitivity::CaseInsensitive) const;
|
||||
|
||||
int to_int(bool& ok) const;
|
||||
unsigned to_uint(bool& ok) const;
|
||||
Optional<int> to_int() const;
|
||||
Optional<unsigned> to_uint() const;
|
||||
|
||||
String to_lowercase() const;
|
||||
String to_uppercase() const;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/Memory.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringUtils.h>
|
||||
#include <AK/StringView.h>
|
||||
|
@ -87,69 +88,54 @@ bool matches(const StringView& str, const StringView& mask, CaseSensitivity case
|
|||
return (mask_ptr == mask_end) && string_ptr == string_end;
|
||||
}
|
||||
|
||||
int convert_to_int(const StringView& str, bool& ok)
|
||||
Optional<int> convert_to_int(const StringView& str)
|
||||
{
|
||||
if (str.is_empty()) {
|
||||
ok = false;
|
||||
return 0;
|
||||
}
|
||||
if (str.is_empty())
|
||||
return {};
|
||||
|
||||
bool negative = false;
|
||||
size_t i = 0;
|
||||
const auto characters = str.characters_without_null_termination();
|
||||
|
||||
if (characters[0] == '-' || characters[0] == '+') {
|
||||
if (str.length() == 1) {
|
||||
ok = false;
|
||||
return 0;
|
||||
}
|
||||
if (str.length() == 1)
|
||||
return {};
|
||||
i++;
|
||||
negative = (characters[0] == '-');
|
||||
}
|
||||
|
||||
int value = 0;
|
||||
for (; i < str.length(); i++) {
|
||||
if (characters[i] < '0' || characters[i] > '9') {
|
||||
ok = false;
|
||||
return 0;
|
||||
}
|
||||
if (characters[i] < '0' || characters[i] > '9')
|
||||
return {};
|
||||
value = value * 10;
|
||||
value += characters[i] - '0';
|
||||
}
|
||||
ok = true;
|
||||
|
||||
return negative ? -value : value;
|
||||
}
|
||||
|
||||
unsigned convert_to_uint(const StringView& str, bool& ok)
|
||||
Optional<unsigned> convert_to_uint(const StringView& str)
|
||||
{
|
||||
if (str.is_empty()) {
|
||||
ok = false;
|
||||
return 0;
|
||||
}
|
||||
if (str.is_empty())
|
||||
return {};
|
||||
|
||||
unsigned value = 0;
|
||||
const auto characters = str.characters_without_null_termination();
|
||||
|
||||
for (size_t i = 0; i < str.length(); i++) {
|
||||
if (characters[i] < '0' || characters[i] > '9') {
|
||||
ok = false;
|
||||
return 0;
|
||||
}
|
||||
if (characters[i] < '0' || characters[i] > '9')
|
||||
return {};
|
||||
|
||||
value = value * 10;
|
||||
value += characters[i] - '0';
|
||||
}
|
||||
ok = true;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned convert_to_uint_from_hex(const StringView& str, bool& ok)
|
||||
Optional<unsigned> convert_to_uint_from_hex(const StringView& str)
|
||||
{
|
||||
if (str.is_empty()) {
|
||||
ok = false;
|
||||
return 0;
|
||||
}
|
||||
if (str.is_empty())
|
||||
return {};
|
||||
|
||||
unsigned value = 0;
|
||||
const auto count = str.length();
|
||||
|
@ -165,14 +151,11 @@ unsigned convert_to_uint_from_hex(const StringView& str, bool& ok)
|
|||
} else if (digit >= 'A' && digit <= 'F') {
|
||||
digit_val = 10 + (digit - 'A');
|
||||
} else {
|
||||
ok = false;
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
value = (value << 4) + digit_val;
|
||||
}
|
||||
|
||||
ok = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ enum class CaseSensitivity {
|
|||
namespace StringUtils {
|
||||
|
||||
bool matches(const StringView& str, const StringView& mask, CaseSensitivity = CaseSensitivity::CaseInsensitive);
|
||||
int convert_to_int(const StringView&, bool& ok);
|
||||
unsigned convert_to_uint(const StringView&, bool& ok);
|
||||
unsigned convert_to_uint_from_hex(const StringView&, bool& ok);
|
||||
Optional<int> convert_to_int(const StringView&);
|
||||
Optional<unsigned> convert_to_uint(const StringView&);
|
||||
Optional<unsigned> convert_to_uint_from_hex(const StringView&);
|
||||
bool equals_ignoring_case(const StringView&, const StringView&);
|
||||
bool ends_with(const StringView& a, const StringView& b, CaseSensitivity);
|
||||
}
|
||||
|
|
|
@ -215,14 +215,14 @@ StringView StringView::substring_view_starting_after_substring(const StringView&
|
|||
return { remaining_characters, remaining_length };
|
||||
}
|
||||
|
||||
int StringView::to_int(bool& ok) const
|
||||
Optional<int> StringView::to_int() const
|
||||
{
|
||||
return StringUtils::convert_to_int(*this, ok);
|
||||
return StringUtils::convert_to_int(*this);
|
||||
}
|
||||
|
||||
unsigned StringView::to_uint(bool& ok) const
|
||||
Optional<unsigned> StringView::to_uint() const
|
||||
{
|
||||
return StringUtils::convert_to_uint(*this, ok);
|
||||
return StringUtils::convert_to_uint(*this);
|
||||
}
|
||||
|
||||
unsigned StringView::hash() const
|
||||
|
|
|
@ -96,8 +96,8 @@ public:
|
|||
// following newline.".
|
||||
Vector<StringView> lines(bool consider_cr = true) const;
|
||||
|
||||
int to_int(bool& ok) const;
|
||||
unsigned to_uint(bool& ok) const;
|
||||
Optional<int> to_int() const;
|
||||
Optional<unsigned> to_uint() const;
|
||||
|
||||
// Create a new substring view of this string view, starting either at the beginning of
|
||||
// the given substring view, or after its end, and continuing until the end of this string
|
||||
|
|
|
@ -72,8 +72,7 @@ TEST_CASE(order)
|
|||
}
|
||||
|
||||
for (int i = 0; i < 10000; ++i) {
|
||||
bool ok;
|
||||
EXPECT_EQ(strings.dequeue().to_int(ok), i);
|
||||
EXPECT_EQ(strings.dequeue().to_int().value(), i);
|
||||
}
|
||||
|
||||
EXPECT(strings.is_empty());
|
||||
|
|
|
@ -127,9 +127,8 @@ TEST_CASE(repeated)
|
|||
|
||||
TEST_CASE(to_int)
|
||||
{
|
||||
bool ok;
|
||||
EXPECT(String("123").to_int(ok) == 123 && ok);
|
||||
EXPECT(String("-123").to_int(ok) == -123 && ok);
|
||||
EXPECT_EQ(String("123").to_int().value(), 123);
|
||||
EXPECT_EQ(String("-123").to_int().value(), -123);
|
||||
}
|
||||
|
||||
TEST_CASE(to_lowercase)
|
||||
|
|
|
@ -69,79 +69,88 @@ TEST_CASE(matches_case_insensitive)
|
|||
|
||||
TEST_CASE(convert_to_int)
|
||||
{
|
||||
bool ok = false;
|
||||
AK::StringUtils::convert_to_int(StringView(), ok);
|
||||
EXPECT(!ok);
|
||||
auto value = AK::StringUtils::convert_to_int(StringView());
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
AK::StringUtils::convert_to_int("", ok);
|
||||
EXPECT(!ok);
|
||||
AK::StringUtils::convert_to_int("");
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
AK::StringUtils::convert_to_int("a", ok);
|
||||
EXPECT(!ok);
|
||||
AK::StringUtils::convert_to_int("a");
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
AK::StringUtils::convert_to_int("+", ok);
|
||||
EXPECT(!ok);
|
||||
AK::StringUtils::convert_to_int("+");
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
AK::StringUtils::convert_to_int("-", ok);
|
||||
EXPECT(!ok);
|
||||
AK::StringUtils::convert_to_int("-");
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
int actual = AK::StringUtils::convert_to_int("0", ok);
|
||||
EXPECT(ok && actual == 0);
|
||||
auto actual = AK::StringUtils::convert_to_int("0");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), 0);
|
||||
|
||||
actual = AK::StringUtils::convert_to_int("1", ok);
|
||||
EXPECT(ok && actual == 1);
|
||||
actual = AK::StringUtils::convert_to_int("1");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), 1);
|
||||
|
||||
actual = AK::StringUtils::convert_to_int("+1", ok);
|
||||
EXPECT(ok && actual == 1);
|
||||
actual = AK::StringUtils::convert_to_int("+1");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), 1);
|
||||
|
||||
actual = AK::StringUtils::convert_to_int("-1", ok);
|
||||
EXPECT(ok && actual == -1);
|
||||
actual = AK::StringUtils::convert_to_int("-1");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), -1);
|
||||
|
||||
actual = AK::StringUtils::convert_to_int("01", ok);
|
||||
EXPECT(ok && actual == 1);
|
||||
actual = AK::StringUtils::convert_to_int("01");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), 1);
|
||||
|
||||
actual = AK::StringUtils::convert_to_int("12345", ok);
|
||||
EXPECT(ok && actual == 12345);
|
||||
actual = AK::StringUtils::convert_to_int("12345");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), 12345);
|
||||
|
||||
actual = AK::StringUtils::convert_to_int("-12345", ok);
|
||||
EXPECT(ok && actual == -12345);
|
||||
actual = AK::StringUtils::convert_to_int("-12345");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), -12345);
|
||||
}
|
||||
|
||||
TEST_CASE(convert_to_uint)
|
||||
{
|
||||
bool ok = false;
|
||||
AK::StringUtils::convert_to_uint(StringView(), ok);
|
||||
EXPECT(!ok);
|
||||
auto value = AK::StringUtils::convert_to_uint(StringView());
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
AK::StringUtils::convert_to_uint("", ok);
|
||||
EXPECT(!ok);
|
||||
value = AK::StringUtils::convert_to_uint("");
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
AK::StringUtils::convert_to_uint("a", ok);
|
||||
EXPECT(!ok);
|
||||
value = AK::StringUtils::convert_to_uint("a");
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
AK::StringUtils::convert_to_uint("+", ok);
|
||||
EXPECT(!ok);
|
||||
value = AK::StringUtils::convert_to_uint("+");
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
AK::StringUtils::convert_to_uint("-", ok);
|
||||
EXPECT(!ok);
|
||||
value = AK::StringUtils::convert_to_uint("-");
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
AK::StringUtils::convert_to_uint("+1", ok);
|
||||
EXPECT(!ok);
|
||||
value = AK::StringUtils::convert_to_uint("+1");
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
AK::StringUtils::convert_to_uint("-1", ok);
|
||||
EXPECT(!ok);
|
||||
AK::StringUtils::convert_to_uint("-1");
|
||||
EXPECT(!value.has_value());
|
||||
|
||||
unsigned actual = AK::StringUtils::convert_to_uint("0", ok);
|
||||
EXPECT(ok && actual == 0u);
|
||||
auto actual = AK::StringUtils::convert_to_uint("0");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), 0u);
|
||||
|
||||
actual = AK::StringUtils::convert_to_uint("1", ok);
|
||||
EXPECT(ok && actual == 1u);
|
||||
actual = AK::StringUtils::convert_to_uint("1");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), 1u);
|
||||
|
||||
actual = AK::StringUtils::convert_to_uint("01", ok);
|
||||
EXPECT(ok && actual == 1u);
|
||||
actual = AK::StringUtils::convert_to_uint("01");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), 1u);
|
||||
|
||||
actual = AK::StringUtils::convert_to_uint("12345", ok);
|
||||
EXPECT(ok && actual == 12345u);
|
||||
actual = AK::StringUtils::convert_to_uint("12345");
|
||||
EXPECT_EQ(actual.has_value(), true);
|
||||
EXPECT_EQ(actual.value(), 12345u);
|
||||
}
|
||||
|
||||
TEST_CASE(ends_with)
|
||||
|
|
|
@ -152,11 +152,11 @@ bool URL::parse(const StringView& string)
|
|||
if (buffer.is_empty())
|
||||
return false;
|
||||
{
|
||||
bool ok;
|
||||
m_port = String::copy(buffer).to_uint(ok);
|
||||
auto port_opt = String::copy(buffer).to_uint();
|
||||
buffer.clear();
|
||||
if (!ok)
|
||||
if (!port_opt.has_value())
|
||||
return false;
|
||||
m_port = port_opt.value();
|
||||
}
|
||||
if (peek() == '/') {
|
||||
state = State::InPath;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/StringUtils.h>
|
||||
|
@ -60,9 +61,8 @@ String urldecode(const StringView& input)
|
|||
builder.append(consume());
|
||||
continue;
|
||||
}
|
||||
bool ok;
|
||||
u8 byte_point = StringUtils::convert_to_uint_from_hex(input.substring_view(cursor + 1, 2), ok);
|
||||
builder.append(byte_point);
|
||||
auto byte_point = StringUtils::convert_to_uint_from_hex(input.substring_view(cursor + 1, 2));
|
||||
builder.append(byte_point.value());
|
||||
consume();
|
||||
consume();
|
||||
consume();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue