summary refs log tree commit diff stats
path: root/lib/pure/cstrutils.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/cstrutils.nim')
-rw-r--r--lib/pure/cstrutils.nim183
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)