Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added simple syncio library #445

Merged
merged 3 commits into from
Feb 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions lib/std/hashes.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
type
Hash* = uint

proc `!&`*(h: Hash; val: uint): Hash {.inline.} =
## Mixes a hash value `h` with `val` to produce a new hash value.
result = h + val
result = result + (result shl 10'u)
result = result xor (result shr 6'u)

proc `!$`*(h: Hash): Hash {.inline.} =
## Finishes the computation of the hash value.
result = h + h shl 3'u
result = result xor (result shr 11'u)
result = result + result shl 15'u

when not defined(nimony):
proc hash*(s: string): Hash =
result = 0'u
for c in items(s):
result = result !& uint(c)
result = !$result

proc hash*(u: uint): Hash {.inline.} = u
when not defined(nimony):
proc hash*(x: int): Hash {.inline.} = cast[Hash](x)

proc hash*(x: int64): Hash {.inline.} = cast[Hash](x)
proc hash*(x: int32): Hash {.inline.} = cast[Hash](int x)
proc hash*(x: char): Hash {.inline.} = Hash(x)
proc hash*(x: bool): Hash {.inline.} = Hash(x)
proc hash*[T: enum](x: T): Hash {.inline.} = Hash(x)

#[
proc hash*[T: object](x: T): Hash {.inline.} =
result = 0'u
for y in fields(x):
result = result !& hash(y)
result = !$result
]#

proc nextTry*(h: Hash; maxHash: int): Hash {.inline.} =
result = (h + 1'u) and maxHash.uint
67 changes: 67 additions & 0 deletions lib/std/intsets.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@

import tables, hashes

const
UIntSize = when defined(cpu16): 16'u
elif defined(cpu32): 32'u
else: 64'u

const
TrunkSize = 8'u
BitsPerTrunk = TrunkSize.uint * UIntSize

type
Trunk = object
a: array[TrunkSize, uint]

IntSet* = object
t: Table[uint, Trunk]

proc initIntSet*(): IntSet = IntSet(t: initTable[uint, Trunk]())

proc split(x: uint): (uint, uint, uint) {.inline.} =
(x div BitsPerTrunk, (x mod BitsPerTrunk) div UIntSize, x mod UIntSize)

proc incl*(s: var IntSet; x: int) =
let (a, b, c) = split cast[uint](x)
let tr = addr(s.t.mgetOrPut(a, default(Trunk)))
tr.a[b] = tr.a[b] or (1'u shl c)

proc excl*(s: var IntSet; x: int) =
let (a, b, c) = split cast[uint](x)
let tr = addr(s.t.mgetOrPut(a, default(Trunk)))
tr.a[b] = tr.a[b] and not (1'u shl c)

proc contains*(s: IntSet; x: int): bool =
let (a, b, c) = split cast[uint](x)
let tr = s.t.getOrDefault(a)
result = (tr.a[b] and (1'u shl c)) != 0'u

proc containsOrIncl*(s: var IntSet; x: int): bool =
let (a, b, c) = split cast[uint](x)
let tr = addr(s.t.mgetOrPut(a, default(Trunk)))
result = (tr.a[b] and (1'u shl c)) != 0'u
if not result:
tr.a[b] = tr.a[b] or (1'u shl c)

when isMainModule:
var s = initIntSet()
for i in 5000..<6000:
s.incl i
assert s.contains i
for i in 500..<600:
s.incl i
assert s.contains i

for i in 50000..<60000:
s.incl i
assert s.contains i

for i in 0..<500:
assert not s.contains i

s.excl 50100
assert not s.contains 50100

assert not containsOrIncl(s, 7)
assert containsOrIncl(s, 7)
126 changes: 126 additions & 0 deletions lib/std/parseopt.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@

when defined(nimony):
import strutils

var
nifcArgc {.importc: "cmdCount".}: int32
nifcArgv {.importc: "cmdLine".}: ptr UncheckedArray[cstring]

proc paramStr*(i: int): string =
if i < nifcArgc and i >= 0:
result = $nifcArgv[i]
else:
result = ""

proc paramCount*(): int =
result = nifcArgc-1

else:
from os import paramStr, paramCount

type
CmdLineKind* = enum ## The detected command line token.
cmdEnd, ## End of command line reached
cmdArgument, ## An argument such as a filename
cmdLongOption, ## A long option such as --option
cmdShortOption ## A short option such as -c

OptParser* = object
pos: int
inShortState: bool
idx: int
kind*: CmdLineKind
key*, val*: string
current: string

proc initOptParser*(): OptParser =
OptParser(pos: 0, inShortState: false, idx: 1, kind: cmdEnd, key: "", val: "", current: "")

proc isKeySep(c: char): bool {.inline.} = c == ':' or c == '='

proc next*(p: var OptParser) =
if p.inShortState and p.pos < p.current.len:
p.kind = cmdShortOption
p.key = $p.current[p.pos]
inc p.pos
if p.pos < p.current.len and p.current[p.pos].isKeySep:
inc p.pos
p.inShortState = false
if p.pos == p.current.len:
p.val = paramStr(p.idx)
inc p.idx
p.pos = 0
else:
p.val = substr(p.current, p.pos, p.current.len-1)
else:
if p.pos == p.current.len:
p.inShortState = false
p.val = ""
else:
p.inShortState = false
if p.idx > paramCount():
p.kind = cmdEnd
return

p.current = paramStr(p.idx)
inc p.idx
if p.current.len >= 2 and p.current[0] == '-' and p.current[1] == '-':
p.kind = cmdLongOption
var last = 2
p.key = ""
var hasValue = false
while last < p.current.len:
if isKeySep(p.current[last]):
hasValue = true
inc last
break
else:
p.key.add p.current[last]
inc last
if not hasValue:
p.val = ""
elif last == p.current.len:
p.val = paramStr(p.idx)
inc p.idx
else:
p.val = substr(p.current, last, p.current.len-1)

elif p.current.len >= 1 and p.current[0] == '-':
p.pos = 1
p.inShortState = true
next p
else:
p.kind = cmdArgument
p.key = move p.current
p.val = ""

iterator getopt*(): (CmdLineKind, string, string) =
var p = initOptParser()
while true:
next(p)
if p.kind == cmdEnd: break
yield (p.kind, p.key, p.val)

when isMainModule:
proc main =
for kind, key, val in getopt():
echo $kind, "##", key, "##", val

main()

# nim c -r lib\std\parseopt.nim --foo:bar -abc: 12 -def -def:5 arg1 arg0 --x: y
#
# produces:
# cmdLongOption##foo##bar
# cmdShortOption##a##
# cmdShortOption##b##
# cmdShortOption##c##12
# cmdShortOption##d##
# cmdShortOption##e##
# cmdShortOption##f##
# cmdShortOption##d##
# cmdShortOption##e##
# cmdShortOption##f##5
# cmdArgument##arg1##
# cmdArgument##arg0##
# cmdLongOption##x##y
27 changes: 27 additions & 0 deletions lib/std/sets.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

import tables

type
HashSet*[T] = object
t: Table[T, bool]

proc initHashSet*[T](): HashSet[T] =
HashSet[T](t: initTable[T, bool]())

proc incl*[T](s: var HashSet[T]; x: sink T) =
s.t[x] = true

proc excl*[T](s: var HashSet[T]; x: T) =
s.t[x] = false

proc contains*[T](s: HashSet[T]; x: T): bool =
s.t.getOrDefault(x)

proc containsOrIncl*[T](s: var HashSet[T]; x: T): bool =
result = contains(s, x)
if not result:
incl s, x

iterator items*[T](s: HashSet[T]): lent T =
for k, v in pairs(s.t):
if v: yield k
40 changes: 40 additions & 0 deletions lib/std/strutils.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

proc endsWith*(s: string; c: char): bool {.inline.} =
if s.len > 0: s[s.len-1] == c else: false

proc strlen*(x: cstring): int {.importc: "strlen", header: "<string.h>".}

proc `$`*(x: cstring): string =
let L = int strlen(x)
result = newString(L)
for i in 0..<result.len:
result[i] = x[i]

proc substr*(s: string; start, stop: int): string =
let newLen = stop - start + 1
result = newString(newLen)
for i in 0 ..< result.len:
result[i] = s[i+start]

func continuesWith*(s, prefix: string; start: int): bool =
if prefix.len > s.len-start:
return false
for i in 0 ..< prefix.len:
if s[i+start] != prefix[i]:
return false
return true

func startsWith*(s, prefix: string): bool =
continuesWith s, prefix, 0

proc toLowerAscii*(c: char): char {.inline.} =
if c >= 'A' and c <= 'Z': char(int(c) - int('A') + int('a'))
else: c

func replace*(s: string; sub, by: char): string =
result = newString(s.len)
var i = 0
while i < s.len:
if s[i] == sub: result[i] = by
else: result[i] = s[i]
inc i
Loading
Loading