From 1ff6230062431aaab2526205bbfa0e5de6e43e9c Mon Sep 17 00:00:00 2001 From: Larpon Date: Sat, 12 Dec 2020 11:10:29 +0100 Subject: [PATCH] builtin: document all functions in string.v (#7273) --- cmd/tools/missdoc.v | 5 +- vlib/builtin/string.v | 215 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 176 insertions(+), 44 deletions(-) diff --git a/cmd/tools/missdoc.v b/cmd/tools/missdoc.v index fe03fe3186..9f8d8b6416 100644 --- a/cmd/tools/missdoc.v +++ b/cmd/tools/missdoc.v @@ -63,10 +63,7 @@ fn report_undocumented_functions_in_path(opt Options, path string) { if !line_above.starts_with('//') { mut tags := []string{} mut grab := true - if line_above.starts_with('[') { // One or more tags - tags << collect_tags(line_above) - } - for j := i - 2; j >= 0; j-- { + for j := i - 1; j >= 0; j-- { prev_line := lines[j] if prev_line.contains('}') { // We've looked back to the above scope, stop here break diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 1d17535e3e..4a930a320e 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -56,7 +56,7 @@ mut: // .is_lit == 0 => a fresh string, should be freed by autofree // .is_lit == 1 => a literal string from .rodata, should NOT be freed // .is_lit == -98761234 => already freed string, protects against double frees. -// ^^^^^^^^^ calling free on these is a bug. +// ---------> ^^^^^^^^^ calling free on these is a bug. // Any other value means that the string has been corrupted. pub struct ustring { pub mut: @@ -65,12 +65,13 @@ pub mut: len int } +// vstrlen returns the V length of the C string `s` (0 terminator is not counted). [unsafe] pub fn vstrlen(s byteptr) int { return unsafe {C.strlen(charptr(s))} } -// Converts a C string to a V string. +// tos converts a C string to a V string. // String data is reused, not copied. [unsafe] pub fn tos(s byteptr, len int) string { @@ -84,11 +85,12 @@ pub fn tos(s byteptr, len int) string { } } +// tos_clone returns a copy of `s`. pub fn tos_clone(s byteptr) string { return tos2(s).clone() } -// Same as `tos`, but calculates the length. Called by `string(bytes)` casts. +// tos2 does the same as `tos`, but also calculates the length. Called by `string(bytes)` casts. // Used only internally. pub fn tos2(s byteptr) string { if s == 0 { @@ -100,7 +102,7 @@ pub fn tos2(s byteptr) string { } } -// Same as `tos2`, but for char*, to avoid warnings +// tos3 does the same as `tos2`, but for char*, to avoid warnings. pub fn tos3(s charptr) string { if s == 0 { panic('tos3: nil string') @@ -111,18 +113,18 @@ pub fn tos3(s charptr) string { } } -// Same as `tos2`, but returns empty string on nil ptr +// tos4 does the same as `tos2`, but returns an empty string on nil ptr. pub fn tos4(s byteptr) string { if s == 0 { - return "" + return '' } return tos2(s) } -// Same as `tos4`, but for char*, to avoid warnings +// tos5 does the same as `tos4`, but for char*, to avoid warnings. pub fn tos5(s charptr) string { if s == 0 { - return "" + return '' } return tos3(s) } @@ -137,7 +139,7 @@ pub fn tos_lit(s charptr) string { } } -// byteptr.vstring() - converts a C style string to a V string. NB: the string data is reused, NOT copied. +// vstring converts a C style string to a V string. NB: the string data is reused, NOT copied. [unsafe] pub fn (bp byteptr) vstring() string { return string{ @@ -146,7 +148,7 @@ pub fn (bp byteptr) vstring() string { } } -// byteptr.vstring_with_len() - converts a C style string to a V string. NB: the string data is reused, NOT copied. +// vstring_with_len converts a C style string to a V string. NB: the string data is reused, NOT copied. [unsafe] pub fn (bp byteptr) vstring_with_len(len int) string { return string{ @@ -155,7 +157,7 @@ pub fn (bp byteptr) vstring_with_len(len int) string { } } -// charptr.vstring() - converts C char* to V string. NB: the string data is reused, NOT copied. +// vstring converts C char* to V string. NB: the string data is reused, NOT copied. [unsafe] pub fn (cp charptr) vstring() string { return string{ @@ -164,7 +166,7 @@ pub fn (cp charptr) vstring() string { } } -// charptr.vstring_with_len() - converts C char* to V string. NB: the string data is reused, NOT copied. +// vstring_with_len converts C char* to V string. NB: the string data is reused, NOT copied. [unsafe] pub fn (cp charptr) vstring_with_len(len int) string { return string{ @@ -173,15 +175,16 @@ pub fn (cp charptr) vstring_with_len(len int) string { } } -// string.clone_static returns an independent copy of a given array +// clone_static returns an independent copy of a given array. // It should be used only in -autofree generated code. fn (a string) clone_static() string { return a.clone() } +// clone returns a copy of the V string `a`. pub fn (a string) clone() string { if a == '' { - // TODO perf? an extra check in each clone() is not nice + // TODO perf? an extra check in each clone() is not nice. return '' } mut b := string{ @@ -201,17 +204,19 @@ pub fn (s string) cstr() byteptr { return clone.str } */ -// cstring_to_vstring creates a copy of cstr and turns it into a v string +// cstring_to_vstring creates a copy of cstr and turns it into a v string. [unsafe] pub fn cstring_to_vstring(cstr byteptr) string { return tos_clone(cstr) } +// replace_once replaces the first occurence of `rep` with the string passed in `with`. pub fn (s string) replace_once(rep string, with string) string { index := s.index(rep) or { return s.clone() } return s.substr(0, index) + with + s.substr(index + rep.len, s.len) } +// replace replaces all occurences of `rep` with the string passed in `with`. pub fn (s string) replace(rep string, with string) string { if s.len == 0 || rep.len == 0 { return s.clone() @@ -277,6 +282,7 @@ struct RepIndex { val_idx int } +// compare_rep_index returns the result of comparing RepIndex `a` and `b`. fn compare_rep_index(a &RepIndex, b &RepIndex) int { if a.idx < b.idx { return -1 @@ -287,6 +293,7 @@ fn compare_rep_index(a &RepIndex, b &RepIndex) int { return 0 } +// sort2 sorts the RepIndex array using `compare_rep_index`. fn (mut a []RepIndex) sort2() { a.sort_with_compare(compare_rep_index) } @@ -297,6 +304,8 @@ fn (a RepIndex) < (b RepIndex) bool { return a.idx < b.idx } */ +// replace_each replaces all occurences of the string pairs given in `vals`. +// Example: assert 'ABCD'.replace_each(['B','C/','C','D','D','C']) == 'AC/DC' pub fn (s string) replace_each(vals []string) string { if s.len == 0 || vals.len == 0 { return s @@ -373,49 +382,59 @@ pub fn (s string) replace_each(vals []string) string { } } +// bool returns `true` if the string equals the word "true" it will return `false` otherwise. pub fn (s string) bool() bool { return s == 'true' || s == 't' // TODO t for pg, remove } +// int returns the value of the string as an integer `'1'.int() == 1`. pub fn (s string) int() int { return int(strconv.common_parse_int(s, 0, 32, false, false)) } +// i64 returns the value of the string as i64 `'1'.i64() == i64(1)`. pub fn (s string) i64() i64 { return strconv.common_parse_int(s, 0, 64, false, false) } +// i8 returns the value of the string as i8 `'1'.i8() == i8(1)`. pub fn (s string) i8() i8 { return i8(strconv.common_parse_int(s, 0, 8, false, false)) } +// i16 returns the value of the string as i16 `'1'.i16() == i16(1)`. pub fn (s string) i16() i16 { return i16(strconv.common_parse_int(s, 0, 16, false, false)) } +// f32 returns the value of the string as f32 `'1.0'.f32() == f32(1)`. pub fn (s string) f32() f32 { // return C.atof(charptr(s.str)) return f32(strconv.atof64(s)) } +// f64 returns the value of the string as f64 `'1.0'.f64() == f64(1)`. pub fn (s string) f64() f64 { // return C.atof(charptr(s.str)) return strconv.atof64(s) } +// u16 returns the value of the string as u16 `'1'.u16() == u16(1)`. pub fn (s string) u16() u16 { return u16(strconv.common_parse_uint(s, 0, 16, false, false)) } +// u32 returns the value of the string as u32 `'1'.u32() == u32(1)`. pub fn (s string) u32() u32 { return u32(strconv.common_parse_uint(s, 0, 32, false, false)) } +// u64 returns the value of the string as u64 `'1'.u64() == u64(1)`. pub fn (s string) u64() u64 { return strconv.common_parse_uint(s, 0, 64, false, false) } -// == +// eq implements the `s == a` (equal) operator. fn (s string) eq(a string) bool { if s.str == 0 { // should never happen @@ -429,12 +448,12 @@ fn (s string) eq(a string) bool { } } -// != +// ne implements the `s != a` (not equal) operator. fn (s string) ne(a string) bool { return !s.eq(a) } -// s < a +// lt implements the `s < a` (less than) operator. fn (s string) lt(a string) bool { for i in 0 .. s.len { if i >= a.len || s[i] > a[i] { @@ -449,22 +468,23 @@ fn (s string) lt(a string) bool { return false } -// s <= a +// le implements the `s <= a` (less than or equal to) operator. fn (s string) le(a string) bool { return s.lt(a) || s.eq(a) } -// s > a +// gt implements the `s > a` (greater than) operator. fn (s string) gt(a string) bool { return !s.le(a) } -// s >= a +// ge implements the `s >= a` (greater than or equal to) operator. fn (s string) ge(a string) bool { return !s.lt(a) } // TODO `fn (s string) + (a string)` ? To be consistent with operator overloading syntax. +// add concatenates string with the string given in `s`. fn (s string) add(a string) string { new_len := a.len + s.len mut res := string{ @@ -487,16 +507,18 @@ fn (s string) add(a string) string { return res } +// split splits the string to an array by `delim`. +// Example: assert 'A B C'.split(' ') == ['A','B','C'] +// If `delim` is empty the string is split by it's characters. +// Example: assert 'DEF'.split('') == ['D','E','F'] pub fn (s string) split(delim string) []string { return s.split_nth(delim, 0) } -/* -split_nth - splits the string based on the passed `delim` substring. -It returns the first Nth parts. When N=0, return all the splits. -The last returned element has the remainder of the string, even if -the remainder contains more `delim` substrings. -*/ +// split_nth splits the string based on the passed `delim` substring. +// It returns the first Nth parts. When N=0, return all the splits. +// The last returned element has the remainder of the string, even if +// the remainder contains more `delim` substrings. pub fn (s string) split_nth(delim string, nth int) []string { mut res := []string{} mut i := 0 @@ -536,7 +558,8 @@ pub fn (s string) split_nth(delim string, nth int) []string { return res } - +// split_into_lines splits the string by newline characters. +// Both `\n` and `\r\n` newline endings is supported. pub fn (s string) split_into_lines() []string { mut res := []string{} if s.len == 0 { @@ -563,7 +586,8 @@ pub fn (s string) split_into_lines() []string { return res } -// 'hello'.left(2) => 'he' +// left returns the `n`th leftmost characters of the string. +// Example: assert 'hello'.left(2) == 'he' fn (s string) left(n int) string { if n >= s.len { return s @@ -571,7 +595,8 @@ fn (s string) left(n int) string { return s.substr(0, n) } -// 'hello'.right(2) => 'llo' +// right returns the `n`th rightmost characters of the string. +// Example: assert 'hello'.right(2) == 'lo' fn (s string) right(n int) string { if n >= s.len { return '' @@ -585,6 +610,8 @@ fn (s string) substr2(start int, _end int, end_max bool) string { return s.substr(start, end) } +// substr returns the string between index positions `start` and `end`. +// Example: assert 'ABCD'.substr(1,3) == 'BC' pub fn (s string) substr(start int, end int) string { $if !no_bounds_checking ? { if start > end || start > s.len || end > s.len || start < 0 || end < 0 { @@ -616,6 +643,7 @@ pub fn (s string) substr(start int, end int) string { return res } +// TODO should probably be deprecated? Not used in the V code base (df4ec89a0) pub fn (s string) index_old(p string) int { if p.len > s.len || p.len == 0 { return -1 @@ -634,6 +662,8 @@ pub fn (s string) index_old(p string) int { return -1 } +// index returns the position of the first character of the input string. +// It will return `none` if the input string can't be found. pub fn (s string) index(p string) ?int { if p.len > s.len || p.len == 0 { return none @@ -652,7 +682,7 @@ pub fn (s string) index(p string) ?int { return none } -// KMP search +// index_kmp does KMP search. fn (s string) index_kmp(p string) int { if p.len > s.len { return -1 @@ -683,6 +713,7 @@ fn (s string) index_kmp(p string) int { return -1 } +// index_any returns the position of any of the characters in the input string - if found. pub fn (s string) index_any(chars string) int { for c in chars { index := s.index(c.str()) or { continue } @@ -691,6 +722,7 @@ pub fn (s string) index_any(chars string) int { return -1 } +// last_index returns the position of the last occurence of the input string. pub fn (s string) last_index(p string) ?int { if p.len > s.len || p.len == 0 { return none @@ -709,6 +741,7 @@ pub fn (s string) last_index(p string) ?int { return none } +// index_after returns the position of the input string, starting search from `start` position. pub fn (s string) index_after(p string, start int) int { if p.len > s.len { return -1 @@ -736,6 +769,8 @@ pub fn (s string) index_after(p string, start int) int { return -1 } +// index_byte returns the index of byte `c` if found in the string. +// index_byte returns -1 if the byte can not be found. pub fn (s string) index_byte(c byte) int { for i in 0 .. s.len { if unsafe {s.str[i]} == c { @@ -745,6 +780,8 @@ pub fn (s string) index_byte(c byte) int { return -1 } +// last_index_byte returns the index of the last occurence of byte `c` if found in the string. +// last_index_byte returns -1 if the byte is not found. pub fn (s string) last_index_byte(c byte) int { for i := s.len - 1; i >= 0; i-- { if unsafe {s.str[i] == c} { @@ -754,7 +791,8 @@ pub fn (s string) last_index_byte(c byte) int { return -1 } -// counts occurrences of substr in s +// count returns the number of occurrences of `substr` in the string. +// count returns -1 if no `substr` could be found. pub fn (s string) count(substr string) int { if s.len == 0 || substr.len == 0 { return 0 @@ -775,6 +813,7 @@ pub fn (s string) count(substr string) int { return 0 // TODO can never get here - v doesn't know that } +// contains returns `true` if the string contains `substr`. pub fn (s string) contains(substr string) bool { if substr.len == 0 { return true @@ -783,6 +822,7 @@ pub fn (s string) contains(substr string) bool { return true } +// contains_any returns `true` if the string contains any chars in `chars`. pub fn (s string) contains_any(chars string) bool { for c in chars { if c.str() in s { @@ -792,6 +832,7 @@ pub fn (s string) contains_any(chars string) bool { return false } +// contains_any_substr returns `true` if the string contains any of the strings in `substrs`. pub fn (s string) contains_any_substr(substrs []string) bool { if substrs.len == 0 { return true @@ -804,6 +845,7 @@ pub fn (s string) contains_any_substr(substrs []string) bool { return false } +// starts_with returns `true` if the string starts with `p`. pub fn (s string) starts_with(p string) bool { if p.len > s.len { return false @@ -816,6 +858,7 @@ pub fn (s string) starts_with(p string) bool { return true } +// ends_with returns `true` if the string ends with `p`. pub fn (s string) ends_with(p string) bool { if p.len > s.len { return false @@ -828,6 +871,7 @@ pub fn (s string) ends_with(p string) bool { return true } +// to_lower returns the string in all lowercase characters. // TODO only works with ASCII pub fn (s string) to_lower() string { unsafe { @@ -839,6 +883,8 @@ pub fn (s string) to_lower() string { } } +// is_lower returns `true` if all characters in the string is lowercase. +// Example: assert 'hello developer'.is_lower() == true pub fn (s string) is_lower() bool { for i in 0 .. s.len { if s[i] >= `A` && s[i] <= `Z` { @@ -848,6 +894,8 @@ pub fn (s string) is_lower() bool { return true } +// to_upper returns the string in all uppercase characters. +// Example: assert 'Hello V'.to_upper() == 'HELLO V' pub fn (s string) to_upper() string { unsafe { mut b := malloc(s.len + 1) @@ -858,6 +906,8 @@ pub fn (s string) to_upper() string { } } +// is_upper returns `true` if all characters in the string is uppercase. +// Example: assert 'HELLO V'.is_upper() == true pub fn (s string) is_upper() bool { for i in 0 .. s.len { if s[i] >= `a` && s[i] <= `z` { @@ -867,6 +917,8 @@ pub fn (s string) is_upper() bool { return true } +// capitalize returns the string with the first character capitalized. +// Example: assert 'hello'.capitalize() == 'Hello' pub fn (s string) capitalize() string { if s.len == 0 { return '' @@ -877,6 +929,8 @@ pub fn (s string) capitalize() string { // return cap } +// is_capital returns `true` if the first character in the string is a capital letter. +// Example: assert 'Hello'.is_capital() == true pub fn (s string) is_capital() bool { if s.len == 0 || !(s[0] >= `A` && s[0] <= `Z`) { return false @@ -889,6 +943,8 @@ pub fn (s string) is_capital() bool { return true } +// title returns the string with each word capitalized. +// Example: assert 'hello v developer'.title() == 'Hello V Developer' pub fn (s string) title() string { words := s.split(' ') mut tit := []string{} @@ -899,6 +955,8 @@ pub fn (s string) title() string { return title } +// is_title returns true if all words of the string is capitalized. +// Example: assert 'Hello V Developer'.is_title() == true pub fn (s string) is_title() bool { words := s.split(' ') for word in words { @@ -909,8 +967,8 @@ pub fn (s string) is_title() bool { return true } -// 'hey [man] how you doin' -// find_between('[', ']') == 'man' +// find_between returns the string found between `start` string and `end` string. +// Example: assert 'hey [man] how you doin'.find_between('[', ']') == 'man' pub fn (s string) find_between(start string, end string) string { start_pos := s.index(start) or { return '' } // First get everything to the right of 'start' @@ -919,6 +977,7 @@ pub fn (s string) find_between(start string, end string) string { return val.left(end_pos) } +// contains returns `true` if `val` string is found in the array. // TODO generic fn (ar []string) contains(val string) bool { for s in ar { @@ -939,16 +998,23 @@ pub fn (a []string) to_c() voidptr { return res } */ +// is_space returns `true` if the byte is a white space character. +// The following list is considered white space characters: ` `, `\n`, `\t`, `\v`, `\f`, `\r`, 0x85, 0xa0 +// Example: assert byte(` `).is_space() == true pub fn (c byte) is_space() bool { // 0x0085 is NEXT LINE (NEL) // 0x00a0 is NO-BREAK SPACE return c in [` `, `\n`, `\t`, `\v`, `\f`, `\r`, 0x85, 0xa0] } +// trim_space strips any of ` `, `\n`, `\t`, `\v`, `\f`, `\r` from the start and end of the string. +// Example: assert ' Hello V '.trim_space() == 'Hello V' pub fn (s string) trim_space() string { return s.trim(' \n\t\v\f\r') } +// trim strips any of the characters given in `cutset` from the start and end of the string. +// Example: assert ' ffHello V ffff'.trim(' f') == 'Hello V' pub fn (s string) trim(cutset string) string { if s.len < 1 || cutset.len < 1 { return s @@ -974,6 +1040,8 @@ pub fn (s string) trim(cutset string) string { return s.substr(pos_left, pos_right + 1) } +// trim_left strips any of the characters given in `cutset` from the left of the string. +// Example: assert 'd Hello V developer'.trim_left(' d') == 'Hello V developer' pub fn (s string) trim_left(cutset string) string { if s.len < 1 || cutset.len < 1 { return s @@ -986,6 +1054,8 @@ pub fn (s string) trim_left(cutset string) string { return s.right(pos) } +// trim_right strips any of the characters given in `cutset` from the right of the string. +// Example: assert ' Hello V d'.trim_right(' d') == ' Hello V' pub fn (s string) trim_right(cutset string) string { if s.len < 1 || cutset.len < 1 { return s @@ -1002,6 +1072,8 @@ pub fn (s string) trim_right(cutset string) string { } } +// trim_prefix strips `str` from the start of the string. +// Example: assert 'WorldHello V'.trim_prefix('World') == 'Hello V' pub fn (s string) trim_prefix(str string) string { if s.starts_with(str) { return s[str.len..] @@ -1009,6 +1081,8 @@ pub fn (s string) trim_prefix(str string) string { return s } +// trim_suffix strips `str` from the end of the string. +// Example: assert 'Hello VWorld'.trim_suffix('World') == 'Hello V' pub fn (s string) trim_suffix(str string) string { if s.ends_with(str) { return s[..s.len - str.len] @@ -1016,6 +1090,7 @@ pub fn (s string) trim_suffix(str string) string { return s } +// compare_strings returns `-1` if `a < b`, `1` if `a > b` else `0`. pub fn compare_strings(a &string, b &string) int { if a.lt(b) { return -1 @@ -1026,6 +1101,7 @@ pub fn compare_strings(a &string, b &string) int { return 0 } +// compare_strings_reverse returns `1` if `a < b`, `-1` if `a > b` else `0`. fn compare_strings_reverse(a &string, b &string) int { if a.lt(b) { return 1 @@ -1036,6 +1112,7 @@ fn compare_strings_reverse(a &string, b &string) int { return 0 } +// compare_strings_by_len returns `-1` if `a.len < b.len`, `1` if `a.len > b.len` else `0`. fn compare_strings_by_len(a &string, b &string) int { if a.len < b.len { return -1 @@ -1046,36 +1123,43 @@ fn compare_strings_by_len(a &string, b &string) int { return 0 } +// compare_lower_strings returns the same as compare_strings but converts `a` and `b` to lower case before comparing. fn compare_lower_strings(a &string, b &string) int { aa := a.to_lower() bb := b.to_lower() return compare_strings(aa, bb) } +// sort sorts the string array. pub fn (mut s []string) sort() { s.sort_with_compare(compare_strings) } +// sort_ignore_case sorts the string array using case insesitive comparing. pub fn (mut s []string) sort_ignore_case() { s.sort_with_compare(compare_lower_strings) } +// sort_by_len sorts the the string array by each string's `.len` length. pub fn (mut s []string) sort_by_len() { s.sort_with_compare(compare_strings_by_len) } +// str returns the string itself. pub fn (s string) str() string { return s } +// str returns the string itself. pub fn (s ustring) str() string { return s.s } +// ustring converts the string to a unicode string. pub fn (s string) ustring() ustring { mut res := ustring{ s: s // runes will have at least s.len elements, save reallocations - // TODO use VLA for small strings? + // TODO use VLA for small strings? runes: __new_array(0, s.len, int(sizeof(int))) } for i := 0; i < s.len; i++ { @@ -1112,6 +1196,7 @@ pub fn (s string) ustring_tmp() ustring { return res } +// eq implements the `u == a` (equal) operator. fn (u ustring) eq(a ustring) bool { if u.len != a.len || u.s != a.s { return false @@ -1119,26 +1204,32 @@ fn (u ustring) eq(a ustring) bool { return true } +// ne implements the `u != a` (not equal) operator. fn (u ustring) ne(a ustring) bool { return !u.eq(a) } +// lt implements the `u < a` (less than) operator. fn (u ustring) lt(a ustring) bool { return u.s < a.s } +// le implements the `u <= a` (less than or equal to) operator. fn (u ustring) le(a ustring) bool { return u.lt(a) || u.eq(a) } +// gt implements the `u > a` (greater than) operator. fn (u ustring) gt(a ustring) bool { return !u.le(a) } +// ge implements the `u >= a` (greater than or equal to) operator. fn (u ustring) ge(a ustring) bool { return !u.lt(a) } +// add concatenates ustring with the string given in `s`. pub fn (u ustring) add(a ustring) ustring { mut res := ustring{ s: u.s + a.s @@ -1162,6 +1253,7 @@ pub fn (u ustring) add(a ustring) ustring { return res } +// index_after returns the position of the input string, starting search from `start` position. pub fn (u ustring) index_after(p ustring, start int) int { if p.len > u.len { return -1 @@ -1189,7 +1281,8 @@ pub fn (u ustring) index_after(p ustring, start int) int { return -1 } -// counts occurrences of substr in s +// count returns the number of occurrences of `substr` in the string. +// count returns -1 if no `substr` could be found. pub fn (u ustring) count(substr ustring) int { if u.len == 0 || substr.len == 0 { return 0 @@ -1210,6 +1303,8 @@ pub fn (u ustring) count(substr ustring) int { return 0 // TODO can never get here - v doesn't know that } +// substr returns the string between index positions `_start` and `_end`. +// Example: assert 'ABCD'.substr(1,3) == 'BC' pub fn (u ustring) substr(_start int, _end int) string { $if !no_bounds_checking ? { if _start > _end || _start > u.len || _end > u.len || _start < 0 || _end < 0 { @@ -1220,6 +1315,8 @@ pub fn (u ustring) substr(_start int, _end int) string { return u.s.substr(u.runes[_start], end) } +// left returns the `n`th leftmost characters of the ustring. +// Example: assert 'hello'.left(2) == 'he' pub fn (u ustring) left(pos int) string { if pos >= u.len { return u.s @@ -1227,6 +1324,8 @@ pub fn (u ustring) left(pos int) string { return u.substr(0, pos) } +// right returns the `n`th rightmost characters of the ustring. +// Example: assert 'hello'.right(2) == 'lo' pub fn (u ustring) right(pos int) string { if pos >= u.len { return '' @@ -1234,6 +1333,8 @@ pub fn (u ustring) right(pos int) string { return u.substr(pos, u.len) } +// at returns the byte at index `idx`. +// Example: assert 'ABC'.at(1) == byte(`B`) fn (s string) at(idx int) byte { $if !no_bounds_checking ? { if idx < 0 || idx >= s.len { @@ -1245,6 +1346,8 @@ fn (s string) at(idx int) byte { } } +// at returns the string at index `idx`. +// Example: assert 'ABC'.at(1) == 'B' pub fn (u ustring) at(idx int) string { $if !no_bounds_checking ? { if idx < 0 || idx >= u.len { @@ -1254,6 +1357,7 @@ pub fn (u ustring) at(idx int) string { return u.substr(idx, idx + 1) } +// free allows for manually freeing the memory occupied by the unicode string. [unsafe] fn (u &ustring) free() { $if prealloc { @@ -1265,26 +1369,37 @@ fn (u &ustring) free() { } } +// is_digit returns `true` if the byte is in range 0-9 and `false` otherwise. +// Example: assert byte(`9`) == true pub fn (c byte) is_digit() bool { return c >= `0` && c <= `9` } +// is_hex_digit returns `true` if the byte is either in range 0-9, a-f or A-F and `false` otherwise. +// Example: assert byte(`F`) == true pub fn (c byte) is_hex_digit() bool { return c.is_digit() || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`) } +// is_oct_digit returns `true` if the byte is in range 0-7 and `false` otherwise. +// Example: assert byte(`7`) == true pub fn (c byte) is_oct_digit() bool { return c >= `0` && c <= `7` } +// is_bin_digit returns `true` if the byte is a binary digit (0 or 1) and `false` otherwise. +// Example: assert byte(`0`) == true pub fn (c byte) is_bin_digit() bool { return c == `0` || c == `1` } +// is_letter returns `true` if the byte is in range a-z or A-Z and `false` otherwise. +// Example: assert byte(`V`) == true pub fn (c byte) is_letter() bool { return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) } +// free allows for manually freeing the memory occupied by the string pub fn (s &string) free() { $if prealloc { return @@ -1300,31 +1415,42 @@ pub fn (s &string) free() { s.is_lit = -98761234 } -// all_before('23:34:45.234', '.') == '23:34:45' +// all_before returns the contents before `dot` in the string. +// Example: assert '23:34:45.234'.all_before('.') == '23:34:45' pub fn (s string) all_before(dot string) string { pos := s.index(dot) or { return s } return s.left(pos) } +// all_before_last returns the contents before the last occurence of `dot` in the string. +// Example: assert '23:34:45.234'.all_before_last(':') == '23:34' pub fn (s string) all_before_last(dot string) string { pos := s.last_index(dot) or { return s } return s.left(pos) } +// all_after returns the contents after `dot` in the string. +// Example: assert '23:34:45.234'.all_after('.') == '234' pub fn (s string) all_after(dot string) string { pos := s.index(dot) or { return s } return s.right(pos + dot.len) } +// all_after_last returns the contents after the last occurence of `dot` in the string. +// Example: assert '23:34:45.234'.all_after_last(':') == '45.234' pub fn (s string) all_after_last(dot string) string { pos := s.last_index(dot) or { return s } return s.right(pos + dot.len) } +// after returns the contents after the last occurence of `dot` in the string. +// Example: assert '23:34:45.234'.after(':') == '45.234' pub fn (s string) after(dot string) string { return s.all_after_last(dot) } +// after_char returns the contents after the first occurence of `dot` character in the string. +// Example: assert '23:34:45.234'.after_char(`:`) == '34:45.234' pub fn (s string) after_char(dot byte) string { mut pos := 0 for i, c in s { @@ -1342,6 +1468,8 @@ pub fn (s string) after_char(dot byte) string { // fn (s []string) substr(a, b int) string { // return join_strings(s.slice_fast(a, b)) // } +// join joins a string array into a string using `del` delimiter. +// Example: assert ['Hello','V'].join(' ') == 'Hello V' pub fn (a []string) join(del string) string { if a.len == 0 { return '' @@ -1380,11 +1508,13 @@ pub fn (a []string) join(del string) string { return res } +// join joins a string array into a string using a `\n` newline delimiter. pub fn (s []string) join_lines() string { return s.join('\n') } -// reverse will return a new reversed string. +// reverse returns a reversed string. +// Example: assert 'Hello V'.reverse() == 'V olleH' pub fn (s string) reverse() string { if s.len == 0 || s.len == 1 { return s @@ -1418,6 +1548,7 @@ pub fn (c byte) is_white() bool { return c.is_space() } +// hash returns an integer hash of the string. pub fn (s string) hash() int { // mut h := s.hash_cache mut h := u32(0) @@ -1429,6 +1560,7 @@ pub fn (s string) hash() int { return int(h) } +// bytes returns the string converted to a byte array. pub fn (s string) bytes() []byte { if s.len == 0 { return [] @@ -1438,7 +1570,7 @@ pub fn (s string) bytes() []byte { return buf } -// repeat returns a new string with a specified number of copies of the string it was called on. +// repeat returns a new string with `count` number of copies of the string it was called on. pub fn (s string) repeat(count int) string { if count < 0 { panic('string.repeat: count is negative: $count') @@ -1462,12 +1594,14 @@ pub fn (s string) repeat(count int) string { } } +// fields returns a string array of the string split by `\t` and ` ` +// Example: assert '\t\tv = v'.fields() == ['', '', 'v', '=', 'v'] pub fn (s string) fields() []string { // TODO do this in a better way return s.replace('\t', ' ').split(' ') } -// Allows multi-line strings to be formatted in a way that removes white-space +// strip_margin allows multi-line strings to be formatted in a way that removes white-space // before a delimeter. by default `|` is used. // Note: the delimiter has to be a byte at this time. That means surrounding // the value in ``. @@ -1484,6 +1618,7 @@ pub fn (s string) strip_margin() string { return s.strip_margin_custom(`|`) } +// strip_margin_custom does the same as `strip_margin` but will use `del` as delimiter instead of `|` pub fn (s string) strip_margin_custom(del byte) string { mut sep := del if sep.is_space() {