v / vlib / strconv / atou.v
98 lines · 85 sloc · 2.91 KB · 4b7955afe528e233a43f8586b923529e6d28c391
Raw
1// Copyright (c) 2019-2024 V language community. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module strconv
5
6// atou_common_check perform basics check on unsigned string to parse.
7// Test emptiness, + sign presence, absence of minus sign, presence of digit after
8// signs and no underscore as first character.
9// returns s first digit index or an error.
10@[direct_array_access]
11fn atou_common_check(s string) !int {
12 if s == '' {
13 return error('strconv.atou: parsing "": empty string')
14 }
15
16 mut start_idx := 0
17
18 if s[0] == `-` {
19 return error('strconv.atou: parsing "{s}" : negative value')
20 }
21
22 if s[0] == `+` {
23 start_idx++
24 }
25
26 if s.len - start_idx < 1 {
27 return error('strconv.atou: parsing "${s}": no number after sign')
28 }
29
30 if s[start_idx] == `_` || s[s.len - 1] == `_` {
31 return error('strconv.atou: parsing "${s}": values cannot start or end with underscores')
32 }
33 return start_idx
34}
35
36// atou_common performs computation for all u8, u16 and u32 type, excluding i64.
37// Parse values, and returns consistent error message over differents types.
38// s is string to parse, max is respective types max value.
39@[direct_array_access]
40fn atou_common(s string, type_max u64) !u64 {
41 mut start_idx := int(atou_common_check(s)!)
42 mut x := u64(0)
43 mut underscored := false
44 for i in start_idx .. s.len {
45 c := s[i] - `0`
46 if c == 47 { // 47 = Ascii(`_`) - ascii(`0`) = 95 - 48.
47 if underscored == true { // Two consecutives underscore
48 return error('strconv.atou: parsing "${s}": consecutives underscores are not allowed')
49 }
50 underscored = true
51 continue // Skip underscore
52 } else {
53 if c > 9 {
54 return error('strconv.atou: parsing "${s}": invalid radix 10 character')
55 }
56 underscored = false
57
58 if x > type_max / 10 {
59 return error('strconv.atou: parsing "${s}": integer overflow')
60 }
61 x *= 10
62 if x > type_max - u64(c) {
63 return error('strconv.atou: parsing "${s}": integer overflow')
64 }
65 x += u64(c)
66 }
67 }
68 return x
69}
70
71// atou8 is equivalent to parse_uint(s, 10, 0), converted to type u8.
72// It returns u8 in range [0..255] or an Error.
73pub fn atou8(s string) !u8 {
74 return u8(atou_common(s, max_u8)!)
75}
76
77// atou16 is equivalent to parse_uint(s, 10, 0), converted to type u16.
78// It returns u16 in range [0..65535] or an Error.
79pub fn atou16(s string) !u16 {
80 return u16(atou_common(s, max_u16)!)
81}
82
83// atou is equivalent to parse_uint(s, 10, 0), converted to type u32.
84pub fn atou(s string) !u32 {
85 return u32(atou_common(s, max_u32)!)
86}
87
88// atou32 is identical to atou. Here to provide a symmetrical API with atoi/atoi32
89// It returns u32 in range [0..4294967295] or an Error.
90pub fn atou32(s string) !u32 {
91 return u32(atou_common(s, max_u32)!)
92}
93
94// atou64 is equivalent to parse_uint(s, 10, 0), converted to type u64.
95// It returns u64 in range [0..18446744073709551615] or an Error.
96pub fn atou64(s string) !u64 {
97 return u64(atou_common(s, max_u64)!)
98}
99