diff options
Diffstat (limited to 'lib/pure/cstrutils.nim')
-rw-r--r-- | lib/pure/cstrutils.nim | 183 |
1 files changed, 102 insertions, 81 deletions
diff --git a/lib/pure/cstrutils.nim b/lib/pure/cstrutils.nim index 601508e2e..c907e54d8 100644 --- a/lib/pure/cstrutils.nim +++ b/lib/pure/cstrutils.nim @@ -7,95 +7,116 @@ # distribution, for details about the copyright. # -## This module supports helper routines for working with ``cstring`` -## without having to convert ``cstring`` to ``string`` in order to +## This module supports helper routines for working with `cstring` +## without having to convert `cstring` to `string`, in order to ## save allocations. +## +## See also +## ======== +## * `strutils module <strutils.html>`_ for working with `string` -include "system/inclrtl" +include system/inclrtl +import std/private/strimpl -proc toLowerAscii(c: char): char {.inline.} = - if c in {'A'..'Z'}: - result = chr(ord(c) + (ord('a') - ord('A'))) - else: - result = c when defined(js): - proc startsWith*(s, prefix: cstring): bool {.noSideEffect, - importjs: "#.startsWith(#)".} + func jsStartsWith(s, prefix: cstring): bool {.importjs: "#.startsWith(#)".} + func jsEndsWith(s, suffix: cstring): bool {.importjs: "#.endsWith(#)".} + - proc endsWith*(s, suffix: cstring): bool {.noSideEffect, - importjs: "#.endsWith(#)".} - - # JS string has more operations that might warrant its own module: - # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String -else: - proc startsWith*(s, prefix: cstring): bool {.noSideEffect, - rtl, extern: "csuStartsWith".} = - ## Returns true if ``s`` starts with ``prefix``. - ## - ## If ``prefix == ""`` true is returned. - ## - ## JS backend uses native ``String.prototype.startsWith``. - var i = 0 - while true: - if prefix[i] == '\0': return true - if s[i] != prefix[i]: return false - inc(i) +func startsWith*(s, prefix: cstring): bool {.rtl, extern: "csuStartsWith".} = + ## Returns true if `s` starts with `prefix`. + ## + ## The JS backend uses the native `String.prototype.startsWith` function. + runnableExamples: + assert startsWith(cstring"Hello, Nimion", cstring"Hello") + assert not startsWith(cstring"Hello, Nimion", cstring"Nimion") + assert startsWith(cstring"Hello", cstring"") - proc endsWith*(s, suffix: cstring): bool {.noSideEffect, - rtl, extern: "csuEndsWith".} = - ## Returns true if ``s`` ends with ``suffix``. - ## - ## If ``suffix == ""`` true is returned. - ## - ## JS backend uses native ``String.prototype.endsWith``. - let slen = s.len - var i = 0 - var j = slen - len(suffix) - while i+j <% slen: - if s[i+j] != suffix[i]: return false - inc(i) - if suffix[i] == '\0': return true + when nimvm: + startsWithImpl(s, prefix) + else: + when defined(js): + result = jsStartsWith(s, prefix) + else: + var i = 0 + while true: + if prefix[i] == '\0': return true + if s[i] != prefix[i]: return false + inc(i) -proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect, - rtl, extern: "csuCmpIgnoreStyle".} = - ## Semantically the same as ``cmp(normalize($a), normalize($b))``. It - ## is just optimized to not allocate temporary strings. This should - ## NOT be used to compare Nim identifier names. use `macros.eqIdent` - ## for that. Returns: +func endsWith*(s, suffix: cstring): bool {.rtl, extern: "csuEndsWith".} = + ## Returns true if `s` ends with `suffix`. ## - ## | 0 if a == b - ## | < 0 if a < b - ## | > 0 if a > b - ## - ## Not supported for JS backend, use `strutils.cmpIgnoreStyle - ## <strutils.html#cmpIgnoreStyle%2Cstring%2Cstring>`_ instead. - var i = 0 - var j = 0 - while true: - while a[i] == '_': inc(i) - while b[j] == '_': inc(j) # BUGFIX: typo - var aa = toLowerAscii(a[i]) - var bb = toLowerAscii(b[j]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) - inc(j) + ## The JS backend uses the native `String.prototype.endsWith` function. + runnableExamples: + assert endsWith(cstring"Hello, Nimion", cstring"Nimion") + assert not endsWith(cstring"Hello, Nimion", cstring"Hello") + assert endsWith(cstring"Hello", cstring"") + + when nimvm: + endsWithImpl(s, suffix) + else: + when defined(js): + result = jsEndsWith(s, suffix) + else: + let slen = s.len + var i = 0 + var j = slen - len(suffix) + while i + j <% slen: + if s[i + j] != suffix[i]: return false + inc(i) + if suffix[i] == '\0': return true -proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect, - rtl, extern: "csuCmpIgnoreCase".} = +func cmpIgnoreStyle*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreStyle".} = + ## Semantically the same as `cmp(normalize($a), normalize($b))`. It + ## is just optimized to not allocate temporary strings. This should + ## NOT be used to compare Nim identifier names, use `macros.eqIdent` + ## for that. Returns: + ## * 0 if `a == b` + ## * < 0 if `a < b` + ## * \> 0 if `a > b` + runnableExamples: + assert cmpIgnoreStyle(cstring"hello", cstring"H_e_L_Lo") == 0 + + when nimvm: + cmpIgnoreStyleImpl(a, b) + else: + when defined(js): + cmpIgnoreStyleImpl(a, b) + else: + var i = 0 + var j = 0 + while true: + while a[i] == '_': inc(i) + while b[j] == '_': inc(j) # BUGFIX: typo + var aa = toLowerAscii(a[i]) + var bb = toLowerAscii(b[j]) + result = ord(aa) - ord(bb) + if result != 0 or aa == '\0': break + inc(i) + inc(j) + +func cmpIgnoreCase*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreCase".} = ## Compares two strings in a case insensitive manner. Returns: - ## - ## | 0 if a == b - ## | < 0 if a < b - ## | > 0 if a > b - ## - ## Not supported for JS backend, use `strutils.cmpIgnoreCase - ## <strutils.html#cmpIgnoreCase%2Cstring%2Cstring>`_ instead. - var i = 0 - while true: - var aa = toLowerAscii(a[i]) - var bb = toLowerAscii(b[i]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) + ## * 0 if `a == b` + ## * < 0 if `a < b` + ## * \> 0 if `a > b` + runnableExamples: + assert cmpIgnoreCase(cstring"hello", cstring"HeLLo") == 0 + assert cmpIgnoreCase(cstring"echo", cstring"hello") < 0 + assert cmpIgnoreCase(cstring"yellow", cstring"hello") > 0 + + when nimvm: + cmpIgnoreCaseImpl(a, b) + else: + when defined(js): + cmpIgnoreCaseImpl(a, b) + else: + var i = 0 + while true: + var aa = toLowerAscii(a[i]) + var bb = toLowerAscii(b[i]) + result = ord(aa) - ord(bb) + if result != 0 or aa == '\0': break + inc(i) |