import strutils type Color* = enum cRed, cGreen, cBlue, cYellow, cPurple ColorStack* = object pieces: array[5, int8] last: int8 proc init*(s: var ColorStack) = for i in 0..4: s.pieces[i] = -1 s.last = -1 proc `[]`*(s: ColorStack, i: Natural): Color = if i > s.last: raise newException(IndexDefect, "index " & $i & " is out of bounds.") result = Color(s.pieces[i]) proc `[]`*(s: ColorStack, i: BackwardsIndex): Color = if s.last == -1: raise newException(IndexDefect, "index out of bounds, the container is empty.") # matching stdlib again result = Color(s.pieces[s.last - int8(i) + 1]) proc `[]=`*(s: var ColorStack, i: Natural, v: Color) = if i > s.last: raise newException(IndexDefect, "index " & $i & " is out of bounds.") s.pieces[i] = int8(v) proc `$`*(s: ColorStack): string = result.add("St@[") for i in 0 .. s.last: let c = Color(s.pieces[i]) result.add($c) if i < s.last: result.add(", ") result.add("]") proc high*(s: ColorStack): int8 = result = s.last proc low*(s: ColorStack): int8 = result = case s.last of -1: 0 # a bit weird but it's how the stdlib seq works else: s.last proc len*(s: ColorStack): int8 = result = s.last + 1 iterator items*(s: ColorStack): Color = for i in 0 .. s.last: yield Color(s[i]) iterator asInt*(s: ColorStack): int8 = for i in 0 .. s.last: yield s.pieces[i] # no conversion, should speed up hashing? maybe iterator pairs*(s: ColorStack): auto = var count = 0 for c in s: yield (count, c) inc count proc add*(s: var ColorStack, c: Color) = let i = s.last + 1 s.pieces[i] = int8(c) # will raise exception if out of bounds s.last = i proc insert*(s: var ColorStack, c: Color, idx: Natural = 0) = for i in countdown(s.last, int8(idx)): swap(s.pieces[i], s.pieces[i + 1]) # will also raise exception if out of bounds s.pieces[idx] = int8(c) inc s.last proc delete*(s: var ColorStack, idx: Natural) = if idx > s.last: raise newException(IndexDefect, "index " & $idx & " is out of bounds.") s.pieces[idx] = -1 dec s.last for i in int8(idx) .. s.last: swap(s.pieces[i], s.pieces[i + 1]) proc find(s: ColorStack, c: Color): int8 = let needle = int(c) for i, v in s.pieces: if v == needle: return i return -1 proc moveSubstack*(src, dst: var ColorStack; start: Natural) = var count = 0 # have to track this separately apparently for idx in (int8(start) .. src.last): swap(src.pieces[idx], dst.pieces[dst.last + 1 + count]) inc count dst.last += int8(count) src.last -= int8(count) proc moveSubstackPre*(src, dst: var ColorStack; start: Natural) = let ssLen = src.last - start + 1 # length of substack for i in countdown(dst.last, 0): swap(dst.pieces[i], dst.pieces[i + ssLen]) var count = 0 for i in start .. src.last: swap(src.pieces[i], dst.pieces[count]) inc count dst.last += int8(ssLen) src.last -= int8(ssLen) proc display(s: ColorStack) = var p: seq[string] for i in s.pieces: if i == -1: p.add("none") else: p.add($Color(i)) echo "pieces: @[", p.join(", "), "], last: ", s.last echo "len: ", s.len, "\n"