indices.nim 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. when not defined(nimHasSystemRaisesDefect):
  2. {.pragma: systemRaisesDefect.}
  3. type
  4. BackwardsIndex* = distinct int ## Type that is constructed by `^` for
  5. ## reversed array accesses.
  6. ## (See `^ template <#^.t,int>`_)
  7. template `^`*(x: int): BackwardsIndex = BackwardsIndex(x)
  8. ## Builtin `roof`:idx: operator that can be used for convenient array access.
  9. ## `a[^x]` is a shortcut for `a[a.len-x]`.
  10. ##
  11. ## ```nim
  12. ## let
  13. ## a = [1, 3, 5, 7, 9]
  14. ## b = "abcdefgh"
  15. ##
  16. ## echo a[^1] # => 9
  17. ## echo b[^2] # => g
  18. ## ```
  19. proc `[]`*[T](s: openArray[T]; i: BackwardsIndex): T {.inline, systemRaisesDefect.} =
  20. system.`[]`(s, s.len - int(i))
  21. proc `[]`*[Idx, T](a: array[Idx, T]; i: BackwardsIndex): T {.inline, systemRaisesDefect.} =
  22. a[Idx(a.len - int(i) + int low(a))]
  23. proc `[]`*(s: string; i: BackwardsIndex): char {.inline, systemRaisesDefect.} = s[s.len - int(i)]
  24. proc `[]`*[T](s: var openArray[T]; i: BackwardsIndex): var T {.inline, systemRaisesDefect.} =
  25. system.`[]`(s, s.len - int(i))
  26. proc `[]`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T {.inline, systemRaisesDefect.} =
  27. a[Idx(a.len - int(i) + int low(a))]
  28. proc `[]`*(s: var string; i: BackwardsIndex): var char {.inline, systemRaisesDefect.} = s[s.len - int(i)]
  29. proc `[]=`*[T](s: var openArray[T]; i: BackwardsIndex; x: T) {.inline, systemRaisesDefect.} =
  30. system.`[]=`(s, s.len - int(i), x)
  31. proc `[]=`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex; x: T) {.inline, systemRaisesDefect.} =
  32. a[Idx(a.len - int(i) + int low(a))] = x
  33. proc `[]=`*(s: var string; i: BackwardsIndex; x: char) {.inline, systemRaisesDefect.} =
  34. s[s.len - int(i)] = x
  35. template `..^`*(a, b: untyped): untyped =
  36. ## A shortcut for `.. ^` to avoid the common gotcha that a space between
  37. ## '..' and '^' is required.
  38. a .. ^b
  39. template `..<`*(a, b: untyped): untyped =
  40. ## A shortcut for `a .. pred(b)`.
  41. ## ```nim
  42. ## for i in 5 ..< 9:
  43. ## echo i # => 5; 6; 7; 8
  44. ## ```
  45. a .. (when b is BackwardsIndex: succ(b) else: pred(b))
  46. template `[]`*(s: string; i: int): char = arrGet(s, i)
  47. template `[]=`*(s: string; i: int; val: char) = arrPut(s, i, val)
  48. template `^^`(s, i: untyped): untyped =
  49. (when i is BackwardsIndex: s.len - int(i) else: int(i))
  50. template spliceImpl(s, a, L, b: typed): untyped =
  51. # make room for additional elements or cut:
  52. var shift = b.len - max(0,L) # ignore negative slice size
  53. var newLen = s.len + shift
  54. if shift > 0:
  55. # enlarge:
  56. setLen(s, newLen)
  57. for i in countdown(newLen-1, a+b.len): movingCopy(s[i], s[i-shift])
  58. else:
  59. for i in countup(a+b.len, newLen-1): movingCopy(s[i], s[i-shift])
  60. # cut down:
  61. setLen(s, newLen)
  62. # fill the hole:
  63. for i in 0 ..< b.len: s[a+i] = b[i]
  64. proc `[]`*[T, U: Ordinal](s: string, x: HSlice[T, U]): string {.inline, systemRaisesDefect.} =
  65. ## Slice operation for strings.
  66. ## Returns the inclusive range `[s[x.a], s[x.b]]`:
  67. ## ```nim
  68. ## var s = "abcdef"
  69. ## assert s[1..3] == "bcd"
  70. ## ```
  71. # Workaround bug #22852
  72. result = ""
  73. let a = s ^^ x.a
  74. let L = (s ^^ x.b) - a + 1
  75. result = newString(L)
  76. for i in 0 ..< L: result[i] = s[i + a]
  77. proc `[]=`*[T, U: Ordinal](s: var string, x: HSlice[T, U], b: string) {.systemRaisesDefect.} =
  78. ## Slice assignment for strings.
  79. ##
  80. ## If `b.len` is not exactly the number of elements that are referred to
  81. ## by `x`, a `splice`:idx: is performed:
  82. ##
  83. runnableExamples:
  84. var s = "abcdefgh"
  85. s[1 .. ^2] = "xyz"
  86. assert s == "axyzh"
  87. var a = s ^^ x.a
  88. var L = (s ^^ x.b) - a + 1
  89. if L == b.len:
  90. for i in 0..<L: s[i+a] = b[i]
  91. else:
  92. spliceImpl(s, a, L, b)
  93. proc `[]`*[Idx, T; U, V: Ordinal](a: array[Idx, T], x: HSlice[U, V]): seq[T] {.systemRaisesDefect.} =
  94. ## Slice operation for arrays.
  95. ## Returns the inclusive range `[a[x.a], a[x.b]]`:
  96. ## ```nim
  97. ## var a = [1, 2, 3, 4]
  98. ## assert a[0..2] == @[1, 2, 3]
  99. ## ```
  100. let xa = a ^^ x.a
  101. let L = (a ^^ x.b) - xa + 1
  102. # Workaround bug #22852:
  103. result = newSeq[T](if L < 0: 0 else: L)
  104. for i in 0..<L: result[i] = a[Idx(i + xa)]
  105. # Workaround bug #22852
  106. discard Natural(L)
  107. proc `[]=`*[Idx, T; U, V: Ordinal](a: var array[Idx, T], x: HSlice[U, V], b: openArray[T]) {.systemRaisesDefect.} =
  108. ## Slice assignment for arrays.
  109. ## ```nim
  110. ## var a = [10, 20, 30, 40, 50]
  111. ## a[1..2] = @[99, 88]
  112. ## assert a == [10, 99, 88, 40, 50]
  113. ## ```
  114. let xa = a ^^ x.a
  115. let L = (a ^^ x.b) - xa + 1
  116. if L == b.len:
  117. for i in 0..<L: a[Idx(i + xa)] = b[i]
  118. else:
  119. sysFatal(RangeDefect, "different lengths for slice assignment")
  120. proc `[]`*[T; U, V: Ordinal](s: openArray[T], x: HSlice[U, V]): seq[T] {.systemRaisesDefect.} =
  121. ## Slice operation for sequences.
  122. ## Returns the inclusive range `[s[x.a], s[x.b]]`:
  123. ## ```nim
  124. ## var s = @[1, 2, 3, 4]
  125. ## assert s[0..2] == @[1, 2, 3]
  126. ## ```
  127. let a = s ^^ x.a
  128. let L = (s ^^ x.b) - a + 1
  129. newSeq(result, L)
  130. for i in 0 ..< L: result[i] = s[i + a]
  131. proc `[]=`*[T; U, V: Ordinal](s: var seq[T], x: HSlice[U, V], b: openArray[T]) {.systemRaisesDefect.} =
  132. ## Slice assignment for sequences.
  133. ##
  134. ## If `b.len` is not exactly the number of elements that are referred to
  135. ## by `x`, a `splice`:idx: is performed.
  136. runnableExamples:
  137. var s = @"abcdefgh"
  138. s[1 .. ^2] = @"xyz"
  139. assert s == @"axyzh"
  140. let a = s ^^ x.a
  141. let L = (s ^^ x.b) - a + 1
  142. if L == b.len:
  143. for i in 0 ..< L: s[i+a] = b[i]
  144. else:
  145. spliceImpl(s, a, L, b)