strimpl.nim 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. func toLowerAscii*(c: char): char {.inline.} =
  2. if c in {'A'..'Z'}:
  3. result = chr(ord(c) + (ord('a') - ord('A')))
  4. else:
  5. result = c
  6. template firstCharCaseSensitiveImpl[T: string | cstring](a, b: T, aLen, bLen: int) =
  7. if aLen == 0 or bLen == 0:
  8. return aLen - bLen
  9. if a[0] != b[0]: return ord(a[0]) - ord(b[0])
  10. template cmpIgnoreStyleImpl*[T: string | cstring](a, b: T,
  11. firstCharCaseSensitive: static bool = false) =
  12. let aLen = a.len
  13. let bLen = b.len
  14. var i = 0
  15. var j = 0
  16. when firstCharCaseSensitive:
  17. firstCharCaseSensitiveImpl(a, b, aLen, bLen)
  18. inc i
  19. inc j
  20. while true:
  21. while i < aLen and a[i] == '_': inc i
  22. while j < bLen and b[j] == '_': inc j
  23. let aa = if i < aLen: toLowerAscii(a[i]) else: '\0'
  24. let bb = if j < bLen: toLowerAscii(b[j]) else: '\0'
  25. result = ord(aa) - ord(bb)
  26. if result != 0: return result
  27. # the characters are identical:
  28. if i >= aLen:
  29. # both cursors at the end:
  30. if j >= bLen: return 0
  31. # not yet at the end of 'b':
  32. return -1
  33. elif j >= bLen:
  34. return 1
  35. inc i
  36. inc j
  37. template cmpIgnoreCaseImpl*[T: string | cstring](a, b: T,
  38. firstCharCaseSensitive: static bool = false) =
  39. let aLen = a.len
  40. let bLen = b.len
  41. var i = 0
  42. when firstCharCaseSensitive:
  43. firstCharCaseSensitiveImpl(a, b, aLen, bLen)
  44. inc i
  45. var m = min(aLen, bLen)
  46. while i < m:
  47. result = ord(toLowerAscii(a[i])) - ord(toLowerAscii(b[i]))
  48. if result != 0: return
  49. inc i
  50. result = aLen - bLen
  51. template startsWithImpl*[T: string | cstring](s, prefix: T) =
  52. let prefixLen = prefix.len
  53. let sLen = s.len
  54. var i = 0
  55. while true:
  56. if i >= prefixLen: return true
  57. if i >= sLen or s[i] != prefix[i]: return false
  58. inc(i)
  59. template endsWithImpl*[T: string | cstring](s, suffix: T) =
  60. let suffixLen = suffix.len
  61. let sLen = s.len
  62. var i = 0
  63. var j = sLen - suffixLen
  64. while i+j >= 0 and i+j < sLen:
  65. if s[i+j] != suffix[i]: return false
  66. inc(i)
  67. if i >= suffixLen: return true
  68. func cmpNimIdentifier*[T: string | cstring](a, b: T): int =
  69. cmpIgnoreStyleImpl(a, b, true)
  70. func c_memchr(cstr: pointer, c: char, n: csize_t): pointer {.
  71. importc: "memchr", header: "<string.h>".}
  72. func c_strstr(haystack, needle: cstring): cstring {.
  73. importc: "strstr", header: "<string.h>".}
  74. func find*(s: cstring, sub: char, start: Natural = 0, last = 0): int =
  75. ## Searches for `sub` in `s` inside the range `start..last` (both ends included).
  76. ## If `last` is unspecified, it defaults to `s.high` (the last element).
  77. ##
  78. ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
  79. ## Otherwise the index returned is relative to `s[0]`, not `start`.
  80. ## Use `s[start..last].rfind` for a `start`-origin index.
  81. let last = if last == 0: s.high else: last
  82. let L = last-start+1
  83. if L > 0:
  84. let found = c_memchr(s[start].unsafeAddr, sub, cast[csize_t](L))
  85. if not found.isNil:
  86. return cast[int](found) -% cast[int](s)
  87. return -1
  88. func find*(s, sub: cstring, start: Natural = 0, last = 0): int =
  89. ## Searches for `sub` in `s` inside the range `start..last` (both ends included).
  90. ## If `last` is unspecified, it defaults to `s.high` (the last element).
  91. ##
  92. ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
  93. ## Otherwise the index returned is relative to `s[0]`, not `start`.
  94. ## Use `s[start..last].find` for a `start`-origin index.
  95. if sub.len > s.len - start: return -1
  96. if sub.len == 1: return find(s, sub[0], start, last)
  97. if last == 0 and s.len > start:
  98. let found = c_strstr(cast[cstring](s[start].unsafeAddr), sub)
  99. if not found.isNil:
  100. result = cast[int](found) -% cast[int](s)
  101. else:
  102. result = -1