mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 20:17:42 +00:00
remove some deprecated pre-1.0 stdlib modules (#20202)
* remove pre-1.0 stdlib deprecations notable exceptions: * ze, toU8 etc in system/arithmetics * potentially callsite * undo macros, ospaths, securehash, oswalkdir * add sets back * add back future, document deprecated versions * add to changelog [skip ci]
This commit is contained in:
@@ -66,13 +66,16 @@
|
||||
- Deprecated `std/sums`.
|
||||
|
||||
[//]: # "Removals:"
|
||||
- Removed deprecated `std/sharedstrings`.
|
||||
- Removed deprecated module `parseopt2`.
|
||||
- Removed deprecated module `sharedstrings`.
|
||||
- Removed deprecated module `dom_extensions`.
|
||||
- Removed deprecated module `LockFreeHash`.
|
||||
- Removed deprecated module `events`.
|
||||
- Removed deprecated `oids.oidToString`.
|
||||
- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`.
|
||||
- Removed deprecated `jsre.test` and `jsre.toString`.
|
||||
- Removed deprecated `math.c_frexp`.
|
||||
- Removed deprecated `` httpcore.`==` ``.
|
||||
- Removed deprecated `std/dom_extensions`.
|
||||
- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types.
|
||||
- Removed deprecated `osproc.poDemon`, symbol with typo.
|
||||
|
||||
|
||||
@@ -1,611 +0,0 @@
|
||||
#nim c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
## Memory Utility Functions
|
||||
|
||||
{.deprecated.}
|
||||
|
||||
import math, hashes
|
||||
|
||||
proc newHeap*[T](): ptr T =
|
||||
result = cast[ptr T](alloc0(sizeof(T)))
|
||||
|
||||
proc copyNew*[T](x: var T): ptr T =
|
||||
var
|
||||
size = sizeof(T)
|
||||
mem = alloc(size)
|
||||
copyMem(mem, x.addr, size)
|
||||
return cast[ptr T](mem)
|
||||
|
||||
proc copyTo*[T](val: var T, dest: int) =
|
||||
copyMem(pointer(dest), val.addr, sizeof(T))
|
||||
|
||||
proc allocType*[T](): pointer = alloc(sizeof(T))
|
||||
|
||||
proc newShared*[T](): ptr T =
|
||||
result = cast[ptr T](allocShared0(sizeof(T)))
|
||||
|
||||
proc copyShared*[T](x: var T): ptr T =
|
||||
var
|
||||
size = sizeof(T)
|
||||
mem = allocShared(size)
|
||||
copyMem(mem, x.addr, size)
|
||||
return cast[ptr T](mem)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
## Pointer arithmetic
|
||||
|
||||
proc `+`*(p: pointer, i: int): pointer {.inline.} =
|
||||
cast[pointer](cast[int](p) + i)
|
||||
|
||||
const
|
||||
minTableSize = 8
|
||||
reProbeLimit = 12
|
||||
minCopyWork = 4096
|
||||
intSize = sizeof(int)
|
||||
|
||||
|
||||
|
||||
when sizeof(int) == 4: # 32bit
|
||||
type
|
||||
Raw = range[0..1073741823]
|
||||
## The range of uint values that can be stored directly in a value slot
|
||||
## when on a 32 bit platform
|
||||
elif sizeof(int) == 8: # 64bit
|
||||
type
|
||||
Raw = range[0'i64..4611686018427387903'i64]
|
||||
## The range of uint values that can be stored directly in a value slot
|
||||
## when on a 64 bit platform
|
||||
else:
|
||||
{.error: "unsupported platform".}
|
||||
|
||||
type
|
||||
Entry = tuple
|
||||
key: int
|
||||
value: int
|
||||
|
||||
EntryArr = ptr array[0..10_000_000, Entry]
|
||||
|
||||
PConcTable[K, V] = ptr object {.pure.}
|
||||
len: int
|
||||
used: int
|
||||
active: int
|
||||
copyIdx: int
|
||||
copyDone: int
|
||||
next: PConcTable[K, V]
|
||||
data: EntryArr
|
||||
|
||||
proc setVal[K, V](table: var PConcTable[K, V], key: int, val: int,
|
||||
expVal: int, match: bool): int
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Create a new table
|
||||
proc newLFTable*[K, V](size: int = minTableSize): PConcTable[K, V] =
|
||||
let
|
||||
dataLen = max(nextPowerOfTwo(size), minTableSize)
|
||||
dataSize = dataLen*sizeof(Entry)
|
||||
dataMem = allocShared0(dataSize)
|
||||
tableSize = 7 * intSize
|
||||
tableMem = allocShared0(tableSize)
|
||||
table = cast[PConcTable[K, V]](tableMem)
|
||||
table.len = dataLen
|
||||
table.used = 0
|
||||
table.active = 0
|
||||
table.copyIdx = 0
|
||||
table.copyDone = 0
|
||||
table.next = nil
|
||||
table.data = cast[EntryArr](dataMem)
|
||||
result = table
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Delete a table
|
||||
proc deleteConcTable[K, V](tbl: PConcTable[K, V]) =
|
||||
deallocShared(tbl.data)
|
||||
deallocShared(tbl)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc `[]`[K, V](table: var PConcTable[K, V], i: int): var Entry {.inline.} =
|
||||
table.data[i]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# State flags stored in ptr
|
||||
|
||||
|
||||
proc pack[T](x: T): int {.inline.} =
|
||||
result = (cast[int](x) shl 2)
|
||||
#echo("packKey ",cast[int](x) , " -> ", result)
|
||||
|
||||
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
|
||||
proc pop(x: int): int {.inline.} =
|
||||
result = x and 0xFFFFFFFC'i32
|
||||
|
||||
# Pop the raw value off of our Key or Val
|
||||
proc popRaw(x: int): int {.inline.} =
|
||||
result = x shr 2
|
||||
|
||||
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
|
||||
proc popPtr[V](x: int): ptr V {.inline.} =
|
||||
result = cast[ptr V](pop(x))
|
||||
#echo("popPtr " & $x & " -> " & $cast[int](result))
|
||||
|
||||
# Ghost (sentinel)
|
||||
# K or V is no longer valid use new table
|
||||
const Ghost = 0xFFFFFFFC
|
||||
proc isGhost(x: int): bool {.inline.} =
|
||||
result = x == 0xFFFFFFFC
|
||||
|
||||
# Tombstone
|
||||
# applied to V = K is dead
|
||||
proc isTomb(x: int): bool {.inline.} =
|
||||
result = (x and 0x00000002) != 0
|
||||
|
||||
proc setTomb(x: int): int {.inline.} =
|
||||
result = x or 0x00000002
|
||||
|
||||
# Prime
|
||||
# K or V is in new table copied from old
|
||||
proc isPrime(x: int): bool {.inline.} =
|
||||
result = (x and 0x00000001) != 0
|
||||
|
||||
proc setPrime(x: int): int {.inline.} =
|
||||
result = x or 0x00000001
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
##This is for i32 only need to override for i64
|
||||
proc hashInt(x: int): int {.inline.} =
|
||||
var h = uint32(x) #shr 2'u32
|
||||
h = h xor (h shr 16'u32)
|
||||
h *= 0x85ebca6b'u32
|
||||
h = h xor (h shr 13'u32)
|
||||
h *= 0xc2b2ae35'u32
|
||||
h = h xor (h shr 16'u32)
|
||||
result = int(h)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc resize[K, V](self: PConcTable[K, V]): PConcTable[K, V] =
|
||||
var next = atomic_load_n(self.next.addr, ATOMIC_RELAXED)
|
||||
#echo("next = " & $cast[int](next))
|
||||
if next != nil:
|
||||
#echo("A new table already exists, copy in progress")
|
||||
return next
|
||||
var
|
||||
oldLen = atomic_load_n(self.len.addr, ATOMIC_RELAXED)
|
||||
newTable = newLFTable[K, V](oldLen*2)
|
||||
success = atomic_compare_exchange_n(self.next.addr, next.addr, newTable,
|
||||
false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||
if not success:
|
||||
echo("someone beat us to it! delete table we just created and return his " &
|
||||
$cast[int](next))
|
||||
deleteConcTable(newTable)
|
||||
return next
|
||||
else:
|
||||
echo("Created New Table! " & $cast[int](newTable) & " Size = " & $newTable.len)
|
||||
return newTable
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#proc keyEQ[K](key1: ptr K, key2: ptr K): bool {.inline.} =
|
||||
proc keyEQ[K](key1: int, key2: int): bool {.inline.} =
|
||||
result = false
|
||||
when K is Raw:
|
||||
if key1 == key2:
|
||||
result = true
|
||||
else:
|
||||
var
|
||||
p1 = popPtr[K](key1)
|
||||
p2 = popPtr[K](key2)
|
||||
if p1 != nil and p2 != nil:
|
||||
if cast[int](p1) == cast[int](p2):
|
||||
return true
|
||||
if p1[] == p2[]:
|
||||
return true
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#proc tableFull(self: var PConcTable[K,V]) : bool {.inline.} =
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc copySlot[K, V](idx: int, oldTbl: var PConcTable[K, V],
|
||||
newTbl: var PConcTable[K, V]): bool =
|
||||
#echo("Copy idx " & $idx)
|
||||
var
|
||||
oldVal = 0
|
||||
oldkey = 0
|
||||
ok = false
|
||||
result = false
|
||||
#Block the key so no other threads waste time here
|
||||
while not ok:
|
||||
ok = atomic_compare_exchange_n(oldTbl[idx].key.addr, oldKey.addr,
|
||||
setTomb(oldKey), false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||
#echo("oldKey was = " & $oldKey & " set it to tomb " & $setTomb(oldKey))
|
||||
#Prevent new values from appearing in the old table by priming
|
||||
oldVal = atomic_load_n(oldTbl[idx].value.addr, ATOMIC_RELAXED)
|
||||
while not isPrime(oldVal):
|
||||
var box = if oldVal == 0 or isTomb(oldVal): oldVal.setTomb.setPrime
|
||||
else: oldVal.setPrime
|
||||
if atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
|
||||
box, false, ATOMIC_RELAXED, ATOMIC_RELAXED):
|
||||
if isPrime(box) and isTomb(box):
|
||||
return true
|
||||
oldVal = box
|
||||
break
|
||||
#echo("oldVal was = ", oldVal, " set it to prime ", box)
|
||||
if isPrime(oldVal) and isTomb(oldVal):
|
||||
#when not (K is Raw):
|
||||
# deallocShared(popPtr[K](oldKey))
|
||||
return false
|
||||
if isTomb(oldVal):
|
||||
echo("oldVal is Tomb!!!, should not happen")
|
||||
if pop(oldVal) != 0:
|
||||
result = setVal(newTbl, pop(oldKey), pop(oldVal), 0, true) == 0
|
||||
#if result:
|
||||
#echo("Copied a Slot! idx= " & $idx & " key= " & $oldKey & " val= " & $oldVal)
|
||||
#else:
|
||||
#echo("copy slot failed")
|
||||
# Our copy is done so we disable the old slot
|
||||
while not ok:
|
||||
ok = atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
|
||||
oldVal.setTomb.setPrime, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||
#echo("disabled old slot")
|
||||
#echo"---------------------"
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc promote[K, V](table: var PConcTable[K, V]) =
|
||||
var
|
||||
newData = atomic_load_n(table.next.data.addr, ATOMIC_RELAXED)
|
||||
newLen = atomic_load_n(table.next.len.addr, ATOMIC_RELAXED)
|
||||
newUsed = atomic_load_n(table.next.used.addr, ATOMIC_RELAXED)
|
||||
|
||||
deallocShared(table.data)
|
||||
atomic_store_n(table.data.addr, newData, ATOMIC_RELAXED)
|
||||
atomic_store_n(table.len.addr, newLen, ATOMIC_RELAXED)
|
||||
atomic_store_n(table.used.addr, newUsed, ATOMIC_RELAXED)
|
||||
atomic_store_n(table.copyIdx.addr, 0, ATOMIC_RELAXED)
|
||||
atomic_store_n(table.copyDone.addr, 0, ATOMIC_RELAXED)
|
||||
deallocShared(table.next)
|
||||
atomic_store_n(table.next.addr, nil, ATOMIC_RELAXED)
|
||||
echo("new table swapped!")
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc checkAndPromote[K, V](table: var PConcTable[K, V], workDone: int): bool =
|
||||
var
|
||||
oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
|
||||
copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
|
||||
ok: bool
|
||||
result = false
|
||||
if workDone > 0:
|
||||
#echo("len to copy =" & $oldLen)
|
||||
#echo("copyDone + workDone = " & $copyDone & " + " & $workDone)
|
||||
while not ok:
|
||||
ok = atomic_compare_exchange_n(table.copyDone.addr, copyDone.addr,
|
||||
copyDone + workDone, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||
#if ok: echo("set copyDone")
|
||||
# If the copy is done we can promote this table
|
||||
if copyDone + workDone >= oldLen:
|
||||
# Swap new data
|
||||
#echo("work is done!")
|
||||
table.promote
|
||||
result = true
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc copySlotAndCheck[K, V](table: var PConcTable[K, V], idx: int):
|
||||
PConcTable[K, V] =
|
||||
var
|
||||
newTable = cast[PConcTable[K, V]](atomic_load_n(table.next.addr,
|
||||
ATOMIC_RELAXED))
|
||||
result = newTable
|
||||
if newTable != nil and copySlot(idx, table, newTable):
|
||||
#echo("copied a single slot, idx = " & $idx)
|
||||
if checkAndPromote(table, 1): return table
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc helpCopy[K, V](table: var PConcTable[K, V]): PConcTable[K, V] =
|
||||
var
|
||||
newTable = cast[PConcTable[K, V]](atomic_load_n(table.next.addr,
|
||||
ATOMIC_RELAXED))
|
||||
result = newTable
|
||||
if newTable != nil:
|
||||
var
|
||||
oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
|
||||
copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
|
||||
copyIdx = 0
|
||||
work = min(oldLen, minCopyWork)
|
||||
#panicStart = -1
|
||||
workDone = 0
|
||||
if copyDone < oldLen:
|
||||
var ok: bool
|
||||
while not ok:
|
||||
ok = atomic_compare_exchange_n(table.copyIdx.addr, copyIdx.addr,
|
||||
copyIdx + work, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||
#echo("copy idx = ", copyIdx)
|
||||
for i in 0..work-1:
|
||||
var idx = (copyIdx + i) and (oldLen - 1)
|
||||
if copySlot(idx, table, newTable):
|
||||
workDone += 1
|
||||
if workDone > 0:
|
||||
#echo("did work ", workDone, " on thread ", cast[int](myThreadID[pointer]()))
|
||||
if checkAndPromote(table, workDone): return table
|
||||
# In case a thread finished all the work then got stalled before promotion
|
||||
if checkAndPromote(table, 0): return table
|
||||
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc setVal[K, V](table: var PConcTable[K, V], key: int, val: int,
|
||||
expVal: int, match: bool): int =
|
||||
#echo("-try set- in table ", " key = ", (popPtr[K](key)[]), " val = ", val)
|
||||
when K is Raw:
|
||||
var idx = hashInt(key)
|
||||
else:
|
||||
var idx = popPtr[K](key)[].hash
|
||||
var
|
||||
nextTable: PConcTable[K, V]
|
||||
probes = 1
|
||||
# spin until we find a key slot or build and jump to next table
|
||||
while true:
|
||||
idx = idx and (table.len - 1)
|
||||
#echo("try set idx = " & $idx & "for" & $key)
|
||||
var
|
||||
probedKey = 0
|
||||
openKey = atomic_compare_exchange_n(table[idx].key.addr, probedKey.addr,
|
||||
key, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||
if openKey:
|
||||
if val.isTomb:
|
||||
#echo("val was tomb, bail, no reason to set an open slot to tomb")
|
||||
return val
|
||||
#increment used slots
|
||||
#echo("found an open slot, total used = " &
|
||||
#$atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED))
|
||||
discard atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED)
|
||||
break # We found an open slot
|
||||
#echo("set idx ", idx, " key = ", key, " probed = ", probedKey)
|
||||
if keyEQ[K](probedKey, key):
|
||||
#echo("we found the matching slot")
|
||||
break # We found a matching slot
|
||||
if (not(expVal != 0 and match)) and (probes >= reProbeLimit or key.isTomb):
|
||||
if key.isTomb: echo("Key is Tombstone")
|
||||
#if probes >= reProbeLimit: echo("Too much probing " & $probes)
|
||||
#echo("try to resize")
|
||||
#create next bigger table
|
||||
nextTable = resize(table)
|
||||
#help do some copying
|
||||
#echo("help copy old table to new")
|
||||
nextTable = helpCopy(table)
|
||||
#now setVal in the new table instead
|
||||
#echo("jumping to next table to set val")
|
||||
return setVal(nextTable, key, val, expVal, match)
|
||||
else:
|
||||
idx += 1
|
||||
probes += 1
|
||||
# Done spinning for a new slot
|
||||
var oldVal = atomic_load_n(table[idx].value.addr, ATOMIC_RELAXED)
|
||||
if val == oldVal:
|
||||
#echo("this val is already in the slot")
|
||||
return oldVal
|
||||
nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST)
|
||||
if nextTable == nil and
|
||||
((oldVal == 0 and
|
||||
(probes >= reProbeLimit or table.used / table.len > 0.8)) or
|
||||
(isPrime(oldVal))):
|
||||
if table.used / table.len > 0.8: echo("resize because usage ratio = " &
|
||||
$(table.used / table.len))
|
||||
if isPrime(oldVal): echo("old val isPrime, should be a rare mem ordering event")
|
||||
nextTable = resize(table)
|
||||
if nextTable != nil:
|
||||
#echo("tomb old slot then set in new table")
|
||||
nextTable = copySlotAndCheck(table, idx)
|
||||
return setVal(nextTable, key, val, expVal, match)
|
||||
# Finally ready to add new val to table
|
||||
while true:
|
||||
if match and oldVal != expVal:
|
||||
#echo("set failed, no match oldVal= " & $oldVal & " expVal= " & $expVal)
|
||||
return oldVal
|
||||
if atomic_compare_exchange_n(table[idx].value.addr, oldVal.addr,
|
||||
val, false, ATOMIC_RELEASE, ATOMIC_RELAXED):
|
||||
#echo("val set at table " & $cast[int](table))
|
||||
if expVal != 0:
|
||||
if (oldVal == 0 or isTomb(oldVal)) and not isTomb(val):
|
||||
discard atomic_add_fetch(table.active.addr, 1, ATOMIC_RELAXED)
|
||||
elif not (oldVal == 0 or isTomb(oldVal)) and isTomb(val):
|
||||
discard atomic_add_fetch(table.active.addr, -1, ATOMIC_RELAXED)
|
||||
if oldVal == 0 and expVal != 0:
|
||||
return setTomb(oldVal)
|
||||
else: return oldVal
|
||||
if isPrime(oldVal):
|
||||
nextTable = copySlotAndCheck(table, idx)
|
||||
return setVal(nextTable, key, val, expVal, match)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc getVal[K, V](table: var PConcTable[K, V], key: int): int =
|
||||
#echo("-try get- key = " & $key)
|
||||
when K is Raw:
|
||||
var idx = hashInt(key)
|
||||
else:
|
||||
var idx = popPtr[K](key)[].hash
|
||||
#echo("get idx ", idx)
|
||||
var
|
||||
probes = 0
|
||||
val: int
|
||||
while true:
|
||||
idx = idx and (table.len - 1)
|
||||
var
|
||||
newTable: PConcTable[K, V] # = atomic_load_n(table.next.addr, ATOMIC_ACQUIRE)
|
||||
probedKey = atomic_load_n(table[idx].key.addr, ATOMIC_SEQ_CST)
|
||||
if keyEQ[K](probedKey, key):
|
||||
#echo("found key after ", probes+1)
|
||||
val = atomic_load_n(table[idx].value.addr, ATOMIC_ACQUIRE)
|
||||
if not isPrime(val):
|
||||
if isTomb(val):
|
||||
#echo("val was tomb but not prime")
|
||||
return 0
|
||||
else:
|
||||
#echo("-GotIt- idx = ", idx, " key = ", key, " val ", val )
|
||||
return val
|
||||
else:
|
||||
newTable = copySlotAndCheck(table, idx)
|
||||
return getVal(newTable, key)
|
||||
else:
|
||||
#echo("probe ", probes, " idx = ", idx, " key = ", key, " found ", probedKey )
|
||||
if probes >= reProbeLimit*4 or key.isTomb:
|
||||
if newTable == nil:
|
||||
#echo("too many probes and no new table ", key, " ", idx )
|
||||
return 0
|
||||
else:
|
||||
newTable = helpCopy(table)
|
||||
return getVal(newTable, key)
|
||||
idx += 1
|
||||
probes += 1
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#proc set*(table: var PConcTable[Raw,Raw], key: Raw, val: Raw) =
|
||||
# discard setVal(table, pack(key), pack(key), 0, false)
|
||||
|
||||
#proc set*[V](table: var PConcTable[Raw,V], key: Raw, val: ptr V) =
|
||||
# discard setVal(table, pack(key), cast[int](val), 0, false)
|
||||
|
||||
proc set*[K, V](table: var PConcTable[K, V], key: var K, val: var V) =
|
||||
when not (K is Raw):
|
||||
var newKey = cast[int](copyShared(key))
|
||||
else:
|
||||
var newKey = pack(key)
|
||||
when not (V is Raw):
|
||||
var newVal = cast[int](copyShared(val))
|
||||
else:
|
||||
var newVal = pack(val)
|
||||
var oldPtr = pop(setVal(table, newKey, newVal, 0, false))
|
||||
#echo("oldPtr = ", cast[int](oldPtr), " newPtr = ", cast[int](newPtr))
|
||||
when not (V is Raw):
|
||||
if newVal != oldPtr and oldPtr != 0:
|
||||
deallocShared(cast[ptr V](oldPtr))
|
||||
|
||||
|
||||
|
||||
proc get*[K, V](table: var PConcTable[K, V], key: var K): V =
|
||||
when not (V is Raw):
|
||||
when not (K is Raw):
|
||||
return popPtr[V](getVal(table, cast[int](key.addr)))[]
|
||||
else:
|
||||
return popPtr[V](getVal(table, pack(key)))[]
|
||||
else:
|
||||
when not (K is Raw):
|
||||
return popRaw(getVal(table, cast[int](key.addr)))
|
||||
else:
|
||||
return popRaw(getVal(table, pack(key)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#proc `[]`[K,V](table: var PConcTable[K,V], key: K): PEntry[K,V] {.inline.} =
|
||||
# getVal(table, key)
|
||||
|
||||
#proc `[]=`[K,V](table: var PConcTable[K,V], key: K, val: V): PEntry[K,V] {.inline.} =
|
||||
# setVal(table, key, val)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#Tests ----------------------------
|
||||
when not defined(testing) and isMainModule:
|
||||
import locks, times, mersenne
|
||||
|
||||
const
|
||||
numTests = 100000
|
||||
numThreads = 10
|
||||
|
||||
|
||||
|
||||
type
|
||||
TestObj = tuple
|
||||
thr: int
|
||||
f0: int
|
||||
f1: int
|
||||
|
||||
Data = tuple[k: string, v: TestObj]
|
||||
PDataArr = array[0..numTests-1, Data]
|
||||
Dict = PConcTable[string, TestObj]
|
||||
|
||||
var
|
||||
thr: array[0..numThreads-1, Thread[Dict]]
|
||||
|
||||
table = newLFTable[string, TestObj](8)
|
||||
rand = newMersenneTwister(2525)
|
||||
|
||||
proc createSampleData(len: int): PDataArr =
|
||||
#result = cast[PDataArr](allocShared0(sizeof(Data)*numTests))
|
||||
for i in 0..len-1:
|
||||
result[i].k = "mark" & $(i+1)
|
||||
#echo("mark" & $(i+1), " ", hash("mark" & $(i+1)))
|
||||
result[i].v.thr = 0
|
||||
result[i].v.f0 = i+1
|
||||
result[i].v.f1 = 0
|
||||
#echo("key = " & $(i+1) & " Val ptr = " & $cast[int](result[i].v.addr))
|
||||
|
||||
|
||||
|
||||
proc threadProc(tp: Dict) {.thread.} =
|
||||
var t = cpuTime();
|
||||
for i in 1..numTests:
|
||||
var key = "mark" & $(i)
|
||||
var got = table.get(key)
|
||||
got.thr = cast[int](myThreadID[pointer]())
|
||||
got.f1 = got.f1 + 1
|
||||
table.set(key, got)
|
||||
t = cpuTime() - t
|
||||
echo t
|
||||
|
||||
|
||||
var testData = createSampleData(numTests)
|
||||
|
||||
for i in 0..numTests-1:
|
||||
table.set(testData[i].k, testData[i].v)
|
||||
|
||||
var i = 0
|
||||
while i < numThreads:
|
||||
createThread(thr[i], threadProc, table)
|
||||
i += 1
|
||||
|
||||
joinThreads(thr)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var fails = 0
|
||||
|
||||
for i in 0..numTests-1:
|
||||
var got = table.get(testData[i].k)
|
||||
if got.f0 != i+1 or got.f1 != numThreads:
|
||||
fails += 1
|
||||
echo(got)
|
||||
|
||||
echo("Failed read or write = ", fails)
|
||||
|
||||
|
||||
#for i in 1..numTests:
|
||||
# echo(i, " = ", hashInt(i) and 8191)
|
||||
|
||||
deleteConcTable(table)
|
||||
@@ -1,104 +0,0 @@
|
||||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2011 Alexander Mitchell-Robinson
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## :Author: Alexander Mitchell-Robinson
|
||||
##
|
||||
## Unstable API.
|
||||
##
|
||||
## This module implements an event system that is not dependent on external
|
||||
## graphical toolkits. It was originally called `NimEE` because
|
||||
## it was inspired by Python's PyEE module. There are two ways you can use
|
||||
## events: one is a python-inspired way; the other is more of a C-style way.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## var ee = initEventEmitter()
|
||||
## var genericargs: EventArgs
|
||||
## proc handleevent(e: EventArgs) =
|
||||
## echo("Handled!")
|
||||
##
|
||||
## # Python way
|
||||
## ee.on("EventName", handleevent)
|
||||
## ee.emit("EventName", genericargs)
|
||||
##
|
||||
## # C/Java way
|
||||
## # Declare a type
|
||||
## type
|
||||
## SomeObject = object of RootObj
|
||||
## SomeEvent: EventHandler
|
||||
## var myobj: SomeObject
|
||||
## myobj.SomeEvent = initEventHandler("SomeEvent")
|
||||
## myobj.SomeEvent.addHandler(handleevent)
|
||||
## ee.emit(myobj.SomeEvent, genericargs)
|
||||
|
||||
{.deprecated.}
|
||||
|
||||
type
|
||||
EventArgs* = object of RootObj ## Base object for event arguments that are passed to callback functions.
|
||||
EventHandler* = tuple[name: string, handlers: seq[proc(e: EventArgs) {.closure.}]] ## An eventhandler for an event.
|
||||
|
||||
type
|
||||
EventEmitter* = object ## An object that fires events and holds event handlers for an object.
|
||||
s: seq[EventHandler]
|
||||
EventError* = object of ValueError
|
||||
|
||||
proc initEventHandler*(name: string): EventHandler =
|
||||
## Initializes an EventHandler with the specified name and returns it.
|
||||
result.handlers = @[]
|
||||
result.name = name
|
||||
|
||||
proc addHandler*(handler: var EventHandler, fn: proc(e: EventArgs) {.closure.}) =
|
||||
## Adds the callback to the specified event handler.
|
||||
handler.handlers.add(fn)
|
||||
|
||||
proc removeHandler*(handler: var EventHandler, fn: proc(e: EventArgs) {.closure.}) =
|
||||
## Removes the callback from the specified event handler.
|
||||
for i in countup(0, len(handler.handlers)-1):
|
||||
if fn == handler.handlers[i]:
|
||||
handler.handlers.del(i)
|
||||
break
|
||||
|
||||
proc containsHandler*(handler: var EventHandler, fn: proc(e: EventArgs) {.closure.}): bool =
|
||||
## Checks if a callback is registered to this event handler.
|
||||
return handler.handlers.contains(fn)
|
||||
|
||||
|
||||
proc clearHandlers*(handler: var EventHandler) =
|
||||
## Clears all of the callbacks from the event handler.
|
||||
setLen(handler.handlers, 0)
|
||||
|
||||
proc getEventHandler(emitter: var EventEmitter, event: string): int =
|
||||
for k in 0..high(emitter.s):
|
||||
if emitter.s[k].name == event: return k
|
||||
return -1
|
||||
|
||||
proc on*(emitter: var EventEmitter, event: string, fn: proc(e: EventArgs) {.closure.}) =
|
||||
## Assigns a event handler with the specified callback. If the event
|
||||
## doesn't exist, it will be created.
|
||||
var i = getEventHandler(emitter, event)
|
||||
if i < 0:
|
||||
var eh = initEventHandler(event)
|
||||
addHandler(eh, fn)
|
||||
emitter.s.add(eh)
|
||||
else:
|
||||
addHandler(emitter.s[i], fn)
|
||||
|
||||
proc emit*(emitter: var EventEmitter, eventhandler: var EventHandler,
|
||||
args: EventArgs) =
|
||||
## Fires an event handler with specified event arguments.
|
||||
for fn in items(eventhandler.handlers): fn(args)
|
||||
|
||||
proc emit*(emitter: var EventEmitter, event: string, args: EventArgs) =
|
||||
## Fires an event handler with specified event arguments.
|
||||
var i = getEventHandler(emitter, event)
|
||||
if i >= 0:
|
||||
emit(emitter, emitter.s[i], args)
|
||||
|
||||
proc initEventEmitter*(): EventEmitter =
|
||||
## Creates and returns a new EventEmitter.
|
||||
result.s = @[]
|
||||
6
lib/deprecated/pure/future.nim
Normal file
6
lib/deprecated/pure/future.nim
Normal file
@@ -0,0 +1,6 @@
|
||||
## This module is a deprecated alias for the `sugar` module. Deprecated since 0.19.0.
|
||||
|
||||
{.deprecated: "Use the new 'sugar' module instead".}
|
||||
|
||||
import sugar
|
||||
export sugar
|
||||
@@ -7,7 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module is deprecated, `import std/os` instead.
|
||||
## This module is deprecated since 0.20.0, `import std/os` instead.
|
||||
|
||||
{.deprecated: "use `std/os` instead".}
|
||||
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module provides the standard Nim command line parser.
|
||||
## It supports one convenience iterator over all command line options and some
|
||||
## lower-level features.
|
||||
##
|
||||
## Supported syntax:
|
||||
##
|
||||
## 1. short options - `-abcd`, where a, b, c, d are names
|
||||
## 2. long option - `--foo:bar`, `--foo=bar` or `--foo`
|
||||
## 3. argument - everything else
|
||||
|
||||
{.deprecated: "Use the 'parseopt' module instead".}
|
||||
{.push debugger: off.}
|
||||
|
||||
include "system/inclrtl"
|
||||
|
||||
import
|
||||
os, strutils
|
||||
|
||||
type
|
||||
CmdLineKind* = enum ## the detected command line token
|
||||
cmdEnd, ## end of command line reached
|
||||
cmdArgument, ## argument detected
|
||||
cmdLongOption, ## a long option `--option` detected
|
||||
cmdShortOption ## a short option `-c` detected
|
||||
OptParser* =
|
||||
object of RootObj ## this object implements the command line parser
|
||||
cmd: seq[string]
|
||||
pos: int
|
||||
remainingShortOptions: string
|
||||
kind*: CmdLineKind ## the detected command line token
|
||||
key*, val*: string ## key and value pair; `key` is the option
|
||||
## or the argument, `value` is not "" if
|
||||
## the option was given a value
|
||||
|
||||
proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
|
||||
## Initializes option parses with cmdline. cmdline should not contain
|
||||
## argument 0 - program name.
|
||||
## If cmdline.len == 0 default to current command line arguments.
|
||||
result.remainingShortOptions = ""
|
||||
when not defined(createNimRtl):
|
||||
if cmdline.len == 0:
|
||||
result.cmd = commandLineParams()
|
||||
return
|
||||
else:
|
||||
assert cmdline != nil, "Cannot determine command line arguments."
|
||||
|
||||
result.cmd = @cmdline
|
||||
|
||||
when not defined(createNimRtl):
|
||||
proc initOptParser*(): OptParser =
|
||||
## Initializes option parser from current command line arguments.
|
||||
return initOptParser(commandLineParams())
|
||||
|
||||
proc next*(p: var OptParser) {.rtl, extern: "npo2$1".}
|
||||
|
||||
proc nextOption(p: var OptParser, token: string, allowEmpty: bool) =
|
||||
for splitchar in [':', '=']:
|
||||
if splitchar in token:
|
||||
let pos = token.find(splitchar)
|
||||
p.key = token[0..pos-1]
|
||||
p.val = token[pos+1..token.len-1]
|
||||
return
|
||||
|
||||
p.key = token
|
||||
if allowEmpty:
|
||||
p.val = ""
|
||||
else:
|
||||
p.remainingShortOptions = token[0..token.len-1]
|
||||
p.next()
|
||||
|
||||
proc next(p: var OptParser) =
|
||||
if p.remainingShortOptions.len != 0:
|
||||
p.kind = cmdShortOption
|
||||
p.key = p.remainingShortOptions[0..0]
|
||||
p.val = ""
|
||||
p.remainingShortOptions = p.remainingShortOptions[1..p.remainingShortOptions.len-1]
|
||||
return
|
||||
|
||||
if p.pos >= p.cmd.len:
|
||||
p.kind = cmdEnd
|
||||
return
|
||||
|
||||
let token = p.cmd[p.pos]
|
||||
p.pos += 1
|
||||
|
||||
if token.startsWith("--"):
|
||||
p.kind = cmdLongOption
|
||||
nextOption(p, token[2..token.len-1], allowEmpty=true)
|
||||
elif token.startsWith("-"):
|
||||
p.kind = cmdShortOption
|
||||
nextOption(p, token[1..token.len-1], allowEmpty=true)
|
||||
else:
|
||||
p.kind = cmdArgument
|
||||
p.key = token
|
||||
p.val = ""
|
||||
|
||||
proc cmdLineRest*(p: OptParser): string {.rtl, extern: "npo2$1".} =
|
||||
## Returns the part of command line string that has not been parsed yet,
|
||||
## properly quoted.
|
||||
return p.cmd[p.pos..p.cmd.len-1].quoteShellCommand
|
||||
|
||||
type
|
||||
GetoptResult* = tuple[kind: CmdLineKind, key, val: string]
|
||||
|
||||
iterator getopt*(p: var OptParser): GetoptResult =
|
||||
## This is an convenience iterator for iterating over the given OptParser object.
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var p = initOptParser("--left --debug:3 -l=4 -r:2")
|
||||
## for kind, key, val in p.getopt():
|
||||
## case kind
|
||||
## of cmdArgument:
|
||||
## filename = key
|
||||
## of cmdLongOption, cmdShortOption:
|
||||
## case key
|
||||
## of "help", "h": writeHelp()
|
||||
## of "version", "v": writeVersion()
|
||||
## of cmdEnd: assert(false) # cannot happen
|
||||
## if filename == "":
|
||||
## # no filename has been given, so we show the help:
|
||||
## writeHelp()
|
||||
p.pos = 0
|
||||
while true:
|
||||
next(p)
|
||||
if p.kind == cmdEnd: break
|
||||
yield (p.kind, p.key, p.val)
|
||||
|
||||
when declared(paramCount):
|
||||
iterator getopt*(): GetoptResult =
|
||||
## This is an convenience iterator for iterating over the command line arguments.
|
||||
## This create a new OptParser object.
|
||||
## See above for a more detailed example
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## for kind, key, val in getopt():
|
||||
## # this will iterate over all arguments passed to the cmdline.
|
||||
## continue
|
||||
##
|
||||
var p = initOptParser()
|
||||
while true:
|
||||
next(p)
|
||||
if p.kind == cmdEnd: break
|
||||
yield (p.kind, p.key, p.val)
|
||||
|
||||
{.pop.}
|
||||
@@ -1,5 +1,6 @@
|
||||
## This module is a deprecated alias for the `sha1` module.
|
||||
## This module is a deprecated alias for the `sha1` module. Deprecated since 0.18.1.
|
||||
|
||||
{.deprecated: "use `std/sha1` instead".}
|
||||
|
||||
include "../std/sha1"
|
||||
import "../std/sha1"
|
||||
export sha1
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
{.deprecated: "Use the new 'sugar' module instead".}
|
||||
|
||||
include sugar
|
||||
@@ -1,6 +1,6 @@
|
||||
# Include file that implements 'getEnv' and friends. Do not import it!
|
||||
|
||||
when not declared(os) and not declared(ospaths):
|
||||
when not declared(os):
|
||||
{.error: "This is an include file for os.nim!".}
|
||||
|
||||
when not defined(nimscript):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Include file that implements 'osErrorMsg' and friends. Do not import it!
|
||||
|
||||
when not declared(os) and not declared(ospaths):
|
||||
when not declared(os):
|
||||
{.error: "This is an include file for os.nim!".}
|
||||
|
||||
when not defined(nimscript):
|
||||
|
||||
@@ -602,7 +602,6 @@ proc makeRawTest(test, options: string, cat: Category): TTest {.used.} =
|
||||
|
||||
# TODO: fix these files
|
||||
const disabledFilesDefault = @[
|
||||
"LockFreeHash.nim",
|
||||
"tableimpl.nim",
|
||||
"setimpl.nim",
|
||||
"hashcommon.nim",
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
discard """
|
||||
output: '''
|
||||
HandlePrintEvent: Output -> Handled print event
|
||||
HandlePrintEvent2: Output -> printing for ME
|
||||
HandlePrintEvent2: Output -> printing for ME
|
||||
'''
|
||||
"""
|
||||
|
||||
import events
|
||||
|
||||
type
|
||||
PrintEventArgs = object of EventArgs
|
||||
user*: string
|
||||
|
||||
proc handleprintevent*(e: EventArgs) =
|
||||
write(stdout, "HandlePrintEvent: Output -> Handled print event\n")
|
||||
|
||||
proc handleprintevent2*(e: EventArgs) =
|
||||
var args: PrintEventArgs = PrintEventArgs(e)
|
||||
write(stdout, "HandlePrintEvent2: Output -> printing for " & args.user)
|
||||
|
||||
var ee = initEventEmitter()
|
||||
|
||||
var eventargs: PrintEventArgs
|
||||
eventargs.user = "ME\n"
|
||||
|
||||
##method one test
|
||||
|
||||
ee.on("print", handleprintevent)
|
||||
ee.on("print", handleprintevent2)
|
||||
|
||||
ee.emit("print", eventargs)
|
||||
|
||||
##method two test
|
||||
|
||||
type
|
||||
SomeObject = object of RootObj
|
||||
printEvent: EventHandler
|
||||
|
||||
var obj: SomeObject
|
||||
obj.printEvent = initEventHandler("print")
|
||||
obj.printEvent.addHandler(handleprintevent2)
|
||||
|
||||
ee.emit(obj.printEvent, eventargs)
|
||||
|
||||
obj.printEvent.removeHandler(handleprintevent2)
|
||||
|
||||
ee.emit(obj.printEvent, eventargs)
|
||||
@@ -1,66 +1,17 @@
|
||||
discard """
|
||||
cmd: "nim $target --threads:on $options $file"
|
||||
errormsg: "illegal recursion in type 'TIRC'"
|
||||
line: 16
|
||||
line: 12
|
||||
"""
|
||||
|
||||
import events
|
||||
import net
|
||||
import strutils
|
||||
import os
|
||||
|
||||
type
|
||||
TMessageReceivedEventArgs = object of EventArgs
|
||||
Nick*: string
|
||||
Message*: string
|
||||
TIRC = object
|
||||
EventEmitter: EventEmitter
|
||||
MessageReceivedHandler*: EventHandler
|
||||
Socket: Socket
|
||||
Thread: Thread[TIRC]
|
||||
|
||||
proc initIRC*(): TIRC =
|
||||
result.Socket = socket()
|
||||
result.EventEmitter = initEventEmitter()
|
||||
result.MessageReceivedHandler = initEventHandler("MessageReceived")
|
||||
|
||||
proc IsConnected*(irc: var TIRC): bool =
|
||||
return running(irc.Thread)
|
||||
|
||||
|
||||
proc sendRaw*(irc: var TIRC, message: string) =
|
||||
irc.Socket.send(message & "\r\L")
|
||||
proc handleData(irc: TIRC) {.thread.} =
|
||||
var connected = False
|
||||
while connected:
|
||||
var tup = @[irc.Socket]
|
||||
var o = select(tup, 200)
|
||||
echo($o)
|
||||
echo($len(tup))
|
||||
if len(tup) == 1:
|
||||
#Connected
|
||||
connected = True
|
||||
|
||||
#Parse data here
|
||||
|
||||
else:
|
||||
#Disconnected
|
||||
connected = False
|
||||
return
|
||||
|
||||
proc Connect*(irc: var TIRC, nick: string, host: string, port: int = 6667) =
|
||||
connect(irc.Socket, host, TPort(port), TDomain.AF_INET)
|
||||
send(irc.Socket,"USER " & nick & " " & nick & " " & nick & " " & nick & "\r\L")
|
||||
send(irc.Socket,"NICK " & nick & "\r\L")
|
||||
var thread: Thread[TIRC]
|
||||
createThread(thread, handleData, irc)
|
||||
irc.Thread = thread
|
||||
|
||||
|
||||
|
||||
|
||||
when true:
|
||||
var irc = initIRC()
|
||||
irc.Connect("AmryBot[Nim]","irc.freenode.net",6667)
|
||||
irc.sendRaw("JOIN #nim")
|
||||
os.Sleep(4000)
|
||||
|
||||
Reference in New Issue
Block a user