Skip to content

Commit

Permalink
StringRef to StringSlice
Browse files Browse the repository at this point in the history
Signed-off-by: Joshua James Venter <[email protected]>
  • Loading branch information
jjvraw committed Jul 13, 2024
1 parent ffc2a5f commit b9af320
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 36 deletions.
70 changes: 36 additions & 34 deletions stdlib/src/builtin/string.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -212,15 +212,15 @@ fn ascii(value: String) -> String:
# ===----------------------------------------------------------------------=== #


fn _atol(str_ref: StringRef, base: Int = 10) raises -> Int:
"""Implementation of `atol` for StringRef inputs.
fn _atol(str_slice: StringSlice, base: Int = 10) raises -> Int:
"""Implementation of `atol` for StringSlice inputs.
Please see its docstring for details.
"""
if (base != 0) and (base < 2 or base > 36):
raise Error("Base must be >= 2 and <= 36, or 0.")
if not str_ref:
raise Error(_str_to_base_error(base, str_ref))
if not str_slice:
raise Error(_str_to_base_error(base, str_slice))

var real_base: Int
var ord_num_max: Int
Expand All @@ -229,11 +229,11 @@ fn _atol(str_ref: StringRef, base: Int = 10) raises -> Int:
var result = 0
var is_negative: Bool = False
var start: Int = 0
var str_len = len(str_ref)
var str_len = len(str_slice)

start, is_negative = _trim_and_handle_sign(str_ref, str_len)
start, is_negative = _trim_and_handle_sign(str_slice, str_len)

start = _handle_base_prefix(start, str_ref, str_len, base)
start = _handle_base_prefix(start, str_slice, str_len, base)

alias ord_0 = ord("0")
# FIXME:
Expand All @@ -242,11 +242,11 @@ fn _atol(str_ref: StringRef, base: Int = 10) raises -> Int:
alias ord_underscore = ord("_")

if base == 0:
var real_base_new_start = _identify_base(str_ref, start)
var real_base_new_start = _identify_base(str_slice, start)
real_base = real_base_new_start[0]
start = real_base_new_start[1]
if real_base == -1:
raise Error(_str_to_base_error(base, str_ref))
raise Error(_str_to_base_error(base, str_slice))
else:
real_base = base

Expand All @@ -259,7 +259,7 @@ fn _atol(str_ref: StringRef, base: Int = 10) raises -> Int:
ord("A") + (real_base - 11),
)

var buff = str_ref.unsafe_ptr()
var buff = str_slice.unsafe_ptr()
var found_valid_chars_after_start = False
var has_space_after_number = False
# single underscores are only allowed between digits
Expand All @@ -270,7 +270,7 @@ fn _atol(str_ref: StringRef, base: Int = 10) raises -> Int:
var ord_current = int(buff[pos])
if ord_current == ord_underscore:
if was_last_digit_underscore:
raise Error(_str_to_base_error(base, str_ref))
raise Error(_str_to_base_error(base, str_slice))
else:
was_last_digit_underscore = True
continue
Expand All @@ -290,53 +290,53 @@ fn _atol(str_ref: StringRef, base: Int = 10) raises -> Int:
start = pos + 1
break
else:
raise Error(_str_to_base_error(base, str_ref))
raise Error(_str_to_base_error(base, str_slice))
if pos + 1 < str_len and not _isspace(buff[pos + 1]):
var nextresult = result * real_base
if nextresult < result:
raise Error(
_str_to_base_error(base, str_ref)
_str_to_base_error(base, str_slice)
+ " String expresses an integer too large to store in Int."
)
result = nextresult

if was_last_digit_underscore or (not found_valid_chars_after_start):
raise Error(_str_to_base_error(base, str_ref))
raise Error(_str_to_base_error(base, str_slice))

if has_space_after_number:
for pos in range(start, str_len):
if not _isspace(buff[pos]):
raise Error(_str_to_base_error(base, str_ref))
raise Error(_str_to_base_error(base, str_slice))
if is_negative:
result = -result
return result


@always_inline
fn _trim_and_handle_sign(str_ref: StringRef, str_len: Int) -> (Int, Bool):
fn _trim_and_handle_sign(str_slice: StringSlice, str_len: Int) -> (Int, Bool):
"""Trims leading whitespace, handles the sign of the number in the string.
Args:
str_ref: A StringRef containing the number to parse.
str_slice: A StringSlice containing the number to parse.
str_len: The length of the string.
Returns:
A tuple containing:
- The starting index of the number after whitespace and sign.
- A boolean indicating whether the number is negative.
"""
var buff = str_ref.unsafe_ptr()
var buff = str_slice.unsafe_ptr()
var start: Int = 0
while start < str_len and _isspace(buff[start]):
start += 1
var p = str_ref[start] == "+"
var n = str_ref[start] == "-"
var p: Bool = buff[start] == ord("+")
var n: Bool = buff[start] == ord("-")
return start + (p or n), n


@always_inline
fn _handle_base_prefix(
pos: Int, str_ref: StringRef, str_len: Int, base: Int
pos: Int, str_slice: StringSlice, str_len: Int, base: Int
) -> Int:
"""Adjusts the starting position if a valid base prefix is present.
Expand All @@ -345,17 +345,18 @@ fn _handle_base_prefix(
Args:
pos: Current position in the string.
str_ref: The input string.
str_slice: The input StringSlice.
str_len: Length of the input string.
base: The specified base.
Returns:
Updated position after the prefix, if applicable.
"""
var start = pos
var buff = str_slice.unsafe_ptr()
if start + 1 < str_len:
var prefix_char = str_ref[start + 1]
if str_ref[start] == "0" and (
var prefix_char = chr(int(buff[start + 1]))
if buff[start] == ord("0") and (
(base == 2 and (prefix_char == "b" or prefix_char == "B"))
or (base == 8 and (prefix_char == "o" or prefix_char == "O"))
or (base == 16 and (prefix_char == "x" or prefix_char == "X"))
Expand All @@ -364,23 +365,24 @@ fn _handle_base_prefix(
return start


fn _str_to_base_error(base: Int, str_ref: StringRef) -> String:
fn _str_to_base_error(base: Int, str_slice: StringSlice) -> String:
return (
"String is not convertible to integer with base "
+ str(base)
+ ": '"
+ str(str_ref)
+ str(str_slice)
+ "'"
)


fn _identify_base(str_ref: StringRef, start: Int) -> Tuple[Int, Int]:
var length = len(str_ref)
fn _identify_base(str_slice: StringSlice, start: Int) -> Tuple[Int, Int]:
var length = len(str_slice)
var buff = str_slice.unsafe_ptr()
# just 1 digit, assume base 10
if start == (length - 1):
return 10, start
if str_ref[start] == "0":
var second_digit = str_ref[start + 1]
if buff[start] == ord("0"):
var second_digit = chr(int(buff[start + 1]))
if second_digit == "b" or second_digit == "B":
return 2, start + 2
if second_digit == "o" or second_digit == "O":
Expand All @@ -390,17 +392,17 @@ fn _identify_base(str_ref: StringRef, start: Int) -> Tuple[Int, Int]:
# checking for special case of all "0", "_" are also allowed
var was_last_character_underscore = False
for i in range(start + 1, length):
if str_ref[i] == "_":
if buff[i] == ord("_"):
if was_last_character_underscore:
return -1, -1
else:
was_last_character_underscore = True
continue
else:
was_last_character_underscore = False
if str_ref[i] != "0":
if buff[i] != ord("0"):
return -1, -1
elif ord("1") <= ord(str_ref[start]) <= ord("9"):
elif ord("1") <= int(buff[start]) <= ord("9"):
return 10, start
else:
return -1, -1
Expand Down Expand Up @@ -443,7 +445,7 @@ fn atol(str: String, base: Int = 10) raises -> Int:
This follows [Python's integer literals](
https://docs.python.org/3/reference/lexical_analysis.html#integers).
"""
return _atol(str._strref_dangerous(), base)
return _atol(str.as_string_slice(), base)


fn _atof_error(str_ref: StringRef) -> Error:
Expand Down
2 changes: 1 addition & 1 deletion stdlib/src/builtin/string_literal.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ struct StringLiteral(
Returns:
An integer value that represents the string, or otherwise raises.
"""
return _atol(self)
return _atol(self.as_string_slice())

@no_inline
fn __str__(self) -> String:
Expand Down
2 changes: 1 addition & 1 deletion stdlib/src/utils/stringref.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ struct StringRef(
Returns:
An integer value that represents the string, or otherwise raises.
"""
return _atol(self)
return atol(self)

@always_inline
fn __len__(self) -> Int:
Expand Down

0 comments on commit b9af320

Please sign in to comment.