cup/fixedseq.nim

150 lines
3.6 KiB
Nim

import random
type
FixedSeq*[Size: static range[0..255], Content] = object
data: array[Size, Content]
len*: uint8
proc `$`*(s: FixedSeq): string =
result.add("FixedSeq[")
for i, item in s:
if i != 0:
result.add(", ")
result.add($item)
result.add("]")
proc `[]`*(s: FixedSeq, idx: Natural): FixedSeq.Content =
when not defined(danger):
if idx.uint8 >= s.len:
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
s.data[idx]
proc `[]`*(s: var FixedSeq, idx: Natural): var FixedSeq.Content =
when not defined(danger):
if idx.uint8 >= s.len:
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
s.data[idx]
proc `[]`*(s: FixedSeq, idx: BackwardsIndex): auto =
when not defined(danger):
if s.len == 0:
raise newException(IndexDefect, "index out of bounds, the container is empty.") # matching stdlib again
s.data[s.len - idx.uint8]
proc `[]=`*(s: var FixedSeq, idx: Natural, v: FixedSeq.Content) =
when not defined(danger):
if idx.uint8 >= s.len:
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
s.data[idx] = v
proc high*(s: FixedSeq): auto =
result = s.len - 1
proc low*(s: FixedSeq): auto =
result = case s.len
of 0: 0 # a bit weird but it's how the stdlib seq works
else: s.len - 1
iterator items*(s: FixedSeq): auto =
for i in 0'u8 ..< s.len:
yield s.data[i]
iterator asInt*(s: FixedSeq): int8 =
for i in 0'u8 ..< s.len:
yield int8(s.data[i]) # now we do have to convert
iterator pairs*(s: FixedSeq): auto =
var count = 0
for c in s:
yield (count, c)
inc count
proc add*(s: var FixedSeq, v: FixedSeq.Content) =
s.data[s.len] = v # will raise exception if out of bounds
inc s.len
proc insert*(s: var FixedSeq, v: FixedSeq.Content, idx: Natural = 0) =
for i in countdown(s.len - 1, idx.uint8):
swap(s.data[i], s.data[i + 1]) # will also raise exception if out of bounds
s.data[idx] = v
inc s.len
proc delete*(s: var FixedSeq, idx: Natural) =
when not defined(danger):
if idx.uint8 >= s.len:
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
dec s.len
for i in idx.uint8 ..< s.len:
swap(s.data[i], s.data[i + 1])
proc clear*(s: var FixedSeq) =
s.len = 0
proc find*(s: FixedSeq, needle: FixedSeq.Content): int =
for i, v in s.data:
if v == needle:
return i
return -1
proc reverse*(s: var FixedSeq; first, last: Natural) =
# copied shamelessly from std/algorithm.nim
var x = first
var y = last
while x < y:
swap(s[x], s[y])
inc x
dec y
proc shuffle*(s: var FixedSeq, r: var Rand) =
when not defined(danger):
if s.len < s.data.len.uint8:
raise newException(IndexDefect, "Cannot shuffle a partially-full FixedSeq")
r.shuffle(s.data)
proc shuffle*(s: var FixedSeq) =
when not defined(danger):
if s.len < s.data.len.uint8:
raise newException(IndexDefect, "Cannot shuffle a partially-full FixedSeq")
shuffle(s.data)
proc moveSubstack*(src, dst: var FixedSeq; start: Natural) =
var count = 0'u8 # have to track this separately apparently
for idx in start ..< src.len:
swap(src.data[idx], dst.data[dst.len + count])
inc count
dst.len += count
src.len -= count
proc moveSubstackPre*(src, dst: var FixedSeq; start: Natural) =
let ssLen = src.len - start.uint8 # length of substack
for i in countdown(dst.len - 1, 0):
swap(dst.data[i], dst.data[i + ssLen])
var count = 0
for i in start ..< src.len:
swap(src.data[i], dst.data[count])
inc count
dst.len += ssLen
src.len -= ssLen