lib: Trim .nim files trailing whitespace
via OSX: find . -name '*.nim' -exec sed -i '' -E 's/[[:space:]]+$//' {} +
This commit is contained in:
parent
d681812465
commit
43bddf62dd
67 changed files with 2435 additions and 2435 deletions
|
|
@ -6,32 +6,32 @@ import unsigned, math, hashes
|
|||
## Memory Utility Functions
|
||||
|
||||
proc newHeap*[T](): ptr T =
|
||||
result = cast[ptr T](alloc0(sizeof(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)
|
||||
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 copyTo*[T](val: var T, dest: int) =
|
||||
copyMem(pointer(dest), val.addr, sizeof(T))
|
||||
|
||||
proc allocType*[T](): pointer = alloc(sizeof(T))
|
||||
proc allocType*[T](): pointer = alloc(sizeof(T))
|
||||
|
||||
proc newShared*[T](): ptr T =
|
||||
result = cast[ptr T](allocShared0(sizeof(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)
|
||||
var
|
||||
size = sizeof(T)
|
||||
mem = allocShared(size)
|
||||
copyMem(mem, x.addr, size)
|
||||
return cast[ptr T](mem)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
## Pointer arithmetic
|
||||
## Pointer arithmetic
|
||||
|
||||
proc `+`*(p: pointer, i: int): pointer {.inline.} =
|
||||
cast[pointer](cast[int](p) + i)
|
||||
|
|
@ -41,11 +41,11 @@ const
|
|||
reProbeLimit = 12
|
||||
minCopyWork = 4096
|
||||
intSize = sizeof(int)
|
||||
|
||||
|
||||
|
||||
|
||||
when sizeof(int) == 4: # 32bit
|
||||
type
|
||||
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
|
||||
|
|
@ -56,40 +56,40 @@ elif sizeof(int) == 8: # 64bit
|
|||
## The range of uint values that can be stored directly in a value slot
|
||||
## when on a 64 bit platform
|
||||
{.deprecated: [TRaw: Raw].}
|
||||
else:
|
||||
else:
|
||||
{.error: "unsupported platform".}
|
||||
|
||||
type
|
||||
|
||||
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]
|
||||
next: PConcTable[K,V]
|
||||
data: EntryArr
|
||||
{.deprecated: [TEntry: Entry, TEntryArr: EntryArr.}
|
||||
|
||||
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
|
||||
expVal: int, match: bool): 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)
|
||||
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 = cast[PConcTable[K,V]](tableMem)
|
||||
table.len = dataLen
|
||||
table.used = 0
|
||||
table.active = 0
|
||||
|
|
@ -99,14 +99,14 @@ proc newLFTable*[K,V](size: int = minTableSize): PConcTable[K,V] =
|
|||
table.data = cast[EntryArr](dataMem)
|
||||
result = table
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Delete a table
|
||||
proc deleteConcTable[K,V](tbl: PConcTable[K,V]) =
|
||||
deallocShared(tbl.data)
|
||||
deallocShared(tbl.data)
|
||||
deallocShared(tbl)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc `[]`[K,V](table: var PConcTable[K,V], i: int): var Entry {.inline.} =
|
||||
table.data[i]
|
||||
|
|
@ -119,15 +119,15 @@ 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
|
||||
# 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
|
||||
# Pop the raw value off of our Key or Val
|
||||
proc popRaw(x: int): int {.inline.} =
|
||||
result = x shr 2
|
||||
result = x shr 2
|
||||
|
||||
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
|
||||
# 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))
|
||||
|
|
@ -136,34 +136,34 @@ proc popPtr[V](x: int): ptr V {.inline.} =
|
|||
# K or V is no longer valid use new table
|
||||
const Ghost = 0xFFFFFFFC
|
||||
proc isGhost(x: int): bool {.inline.} =
|
||||
result = x == 0xFFFFFFFC
|
||||
result = x == 0xFFFFFFFC
|
||||
|
||||
# Tombstone
|
||||
# applied to V = K is dead
|
||||
proc isTomb(x: int): bool {.inline.} =
|
||||
# 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.} =
|
||||
# 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
|
||||
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)
|
||||
h = h xor (h shr 16'u32)
|
||||
result = int(h)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
@ -175,31 +175,31 @@ proc resize[K,V](self: PConcTable[K,V]): PConcTable[K,V] =
|
|||
#echo("A new table already exists, copy in progress")
|
||||
return next
|
||||
var
|
||||
oldLen = atomic_load_n(self.len.addr, ATOMIC_RELAXED)
|
||||
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
|
||||
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.} =
|
||||
#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:
|
||||
if key1 == key2:
|
||||
result = true
|
||||
else:
|
||||
var
|
||||
var
|
||||
p1 = popPtr[K](key1)
|
||||
p2 = popPtr[K](key2)
|
||||
if p1 != nil and p2 != nil:
|
||||
if p1 != nil and p2 != nil:
|
||||
if cast[int](p1) == cast[int](p2):
|
||||
return true
|
||||
if p1[] == p2[]:
|
||||
|
|
@ -214,53 +214,53 @@ proc keyEQ[K](key1: int, key2: int): bool {.inline.} =
|
|||
|
||||
proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable[K,V]): bool =
|
||||
#echo("Copy idx " & $idx)
|
||||
var
|
||||
var
|
||||
oldVal = 0
|
||||
oldkey = 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,
|
||||
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
|
||||
#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,
|
||||
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):
|
||||
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):
|
||||
if isPrime(oldVal) and isTomb(oldVal):
|
||||
#when not (K is Raw):
|
||||
# deallocShared(popPtr[K](oldKey))
|
||||
# deallocShared(popPtr[K](oldKey))
|
||||
return false
|
||||
if isTomb(oldVal):
|
||||
if isTomb(oldVal):
|
||||
echo("oldVal is Tomb!!!, should not happen")
|
||||
if pop(oldVal) != 0:
|
||||
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")
|
||||
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,
|
||||
ok = atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
|
||||
oldVal.setTomb.setPrime , false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||
#echo("disabled old slot")
|
||||
#echo"---------------------"
|
||||
#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)
|
||||
newLen = atomic_load_n(table.next.len.addr, ATOMIC_RELAXED)
|
||||
newUsed = atomic_load_n(table.next.used.addr, ATOMIC_RELAXED)
|
||||
|
||||
deallocShared(table.data)
|
||||
|
|
@ -270,52 +270,52 @@ proc promote[K,V](table: var PConcTable[K,V]) =
|
|||
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)
|
||||
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
|
||||
|
||||
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
|
||||
result = false
|
||||
if workDone > 0:
|
||||
#echo("len to copy =" & $oldLen)
|
||||
#echo("copyDone + workDone = " & $copyDone & " + " & $workDone)
|
||||
#echo("copyDone + workDone = " & $copyDone & " + " & $workDone)
|
||||
while not ok:
|
||||
ok = atomic_compare_exchange_n(table.copyDone.addr, copyDone.addr,
|
||||
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 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!")
|
||||
#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)
|
||||
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)
|
||||
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)
|
||||
|
|
@ -324,54 +324,54 @@ proc helpCopy[K,V](table: var PConcTable[K,V]): PConcTable[K,V] =
|
|||
if copyDone < oldLen:
|
||||
var ok: bool
|
||||
while not ok:
|
||||
ok = atomic_compare_exchange_n(table.copyIdx.addr, copyIdx.addr,
|
||||
ok = atomic_compare_exchange_n(table.copyIdx.addr, copyIdx.addr,
|
||||
copyIdx + work, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||
#echo("copy idx = ", copyIdx)
|
||||
#echo("copy idx = ", copyIdx)
|
||||
for i in 0..work-1:
|
||||
var idx = (copyIdx + i) and (oldLen - 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
|
||||
# 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)
|
||||
#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]
|
||||
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)
|
||||
# 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)
|
||||
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 = " &
|
||||
#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)
|
||||
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
|
||||
#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)
|
||||
|
|
@ -379,22 +379,22 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
|
|||
#create next bigger table
|
||||
nextTable = resize(table)
|
||||
#help do some copying
|
||||
#echo("help copy old table to new")
|
||||
nextTable = helpCopy(table)
|
||||
#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)
|
||||
#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)
|
||||
var oldVal = atomic_load_n(table[idx].value.addr, ATOMIC_RELAXED)
|
||||
if val == oldVal:
|
||||
#echo("this val is alredy in the slot")
|
||||
#echo("this val is alredy in the slot")
|
||||
return oldVal
|
||||
nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST)
|
||||
if nextTable == nil and
|
||||
((oldVal == 0 and
|
||||
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 = " &
|
||||
|
|
@ -402,7 +402,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
|
|||
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")
|
||||
#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
|
||||
|
|
@ -410,7 +410,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
|
|||
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,
|
||||
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:
|
||||
|
|
@ -427,48 +427,48 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
|
|||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
|
||||
proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
|
||||
#echo("-try get- key = " & $key)
|
||||
when K is Raw:
|
||||
when K is Raw:
|
||||
var idx = hashInt(key)
|
||||
else:
|
||||
var idx = popPtr[K](key)[].hash
|
||||
#echo("get idx ", idx)
|
||||
var
|
||||
var idx = popPtr[K](key)[].hash
|
||||
#echo("get idx ", idx)
|
||||
var
|
||||
probes = 0
|
||||
val: int
|
||||
val: int
|
||||
while true:
|
||||
idx = idx and (table.len - 1)
|
||||
var
|
||||
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)
|
||||
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")
|
||||
#echo("val was tomb but not prime")
|
||||
return 0
|
||||
else:
|
||||
#echo("-GotIt- idx = ", idx, " key = ", key, " val ", val )
|
||||
#echo("-GotIt- idx = ", idx, " key = ", key, " val ", val )
|
||||
return val
|
||||
else:
|
||||
newTable = copySlotAndCheck(table, idx)
|
||||
return getVal(newTable, key)
|
||||
return getVal(newTable, key)
|
||||
else:
|
||||
#echo("probe ", probes, " idx = ", idx, " key = ", key, " found ", probedKey )
|
||||
#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:
|
||||
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)
|
||||
|
||||
|
|
@ -476,33 +476,34 @@ proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
|
|||
# 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):
|
||||
when not (K is Raw):
|
||||
var newKey = cast[int](copyShared(key))
|
||||
else:
|
||||
else:
|
||||
var newKey = pack(key)
|
||||
when not (V is Raw):
|
||||
when not (V is Raw):
|
||||
var newVal = cast[int](copyShared(val))
|
||||
else:
|
||||
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:
|
||||
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:
|
||||
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)))
|
||||
else:
|
||||
return popRaw(getVal(table, pack(key)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -512,7 +513,6 @@ proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
#proc `[]`[K,V](table: var PConcTable[K,V], key: K): PEntry[K,V] {.inline.} =
|
||||
# getVal(table, key)
|
||||
|
|
@ -528,16 +528,16 @@ proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
|
|||
#Tests ----------------------------
|
||||
when not defined(testing) and isMainModule:
|
||||
import locks, times, mersenne
|
||||
|
||||
const
|
||||
|
||||
const
|
||||
numTests = 100000
|
||||
numThreads = 10
|
||||
|
||||
|
||||
|
||||
|
||||
type
|
||||
TestObj = tuple
|
||||
thr: int
|
||||
thr: int
|
||||
f0: int
|
||||
f1: int
|
||||
|
||||
|
|
@ -545,63 +545,63 @@ when not defined(testing) and isMainModule:
|
|||
PDataArr = array[0..numTests-1, Data]
|
||||
Dict = PConcTable[string,TestObj]
|
||||
{.deprecated: [TTestObj: TestObj, TData: Data].}
|
||||
|
||||
var
|
||||
|
||||
var
|
||||
thr: array[0..numThreads-1, Thread[Dict]]
|
||||
|
||||
table = newLFTable[string,TestObj](8)
|
||||
|
||||
table = newLFTable[string,TestObj](8)
|
||||
rand = newMersenneTwister(2525)
|
||||
|
||||
proc createSampleData(len: int): PDataArr =
|
||||
#result = cast[PDataArr](allocShared0(sizeof(Data)*numTests))
|
||||
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)))
|
||||
#echo("mark" & $(i+1), " ", hash("mark" & $(i+1)))
|
||||
result[i].v.thr = 0
|
||||
result[i].v.f0 = i+1
|
||||
result[i].v.f1 = 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();
|
||||
proc threadProc(tp: Dict) {.thread.} =
|
||||
var t = cpuTime();
|
||||
for i in 1..numTests:
|
||||
var key = "mark" & $(i)
|
||||
var got = table.get(key)
|
||||
var got = table.get(key)
|
||||
got.thr = cast[int](myThreadID[pointer]())
|
||||
got.f1 = got.f1 + 1
|
||||
got.f1 = got.f1 + 1
|
||||
table.set(key, got)
|
||||
t = cpuTime() - t
|
||||
echo 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)
|
||||
joinThreads(thr)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var fails = 0
|
||||
|
||||
for i in 0..numTests-1:
|
||||
var got = table.get(testData[i].k)
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ type
|
|||
otherbits: char
|
||||
case isLeaf: bool
|
||||
of false: child: array[0..1, ref NodeObj[T]]
|
||||
of true:
|
||||
of true:
|
||||
key: string
|
||||
when T isnot void:
|
||||
val: T
|
||||
|
||||
|
||||
Node[T] = ref NodeObj[T]
|
||||
CritBitTree*[T] = object ## The crit bit tree can either be used
|
||||
## as a mapping from strings to
|
||||
|
|
@ -66,7 +66,7 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
|
|||
let ch = if it.byte < key.len: key[it.byte] else: '\0'
|
||||
let dir = (1 + (ch.ord or it.otherBits.ord)) shr 8
|
||||
it = it.child[dir]
|
||||
|
||||
|
||||
var newOtherBits = 0
|
||||
var newByte = 0
|
||||
block blockX:
|
||||
|
|
@ -84,7 +84,7 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
|
|||
newOtherBits = newOtherBits xor 255
|
||||
let ch = it.key[newByte]
|
||||
let dir = (1 + (ord(ch) or newOtherBits)) shr 8
|
||||
|
||||
|
||||
var inner: Node[T]
|
||||
new inner
|
||||
new result
|
||||
|
|
@ -93,7 +93,7 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
|
|||
inner.otherBits = chr(newOtherBits)
|
||||
inner.byte = newByte
|
||||
inner.child[1 - dir] = result
|
||||
|
||||
|
||||
var wherep = addr(c.root)
|
||||
while true:
|
||||
var p = wherep[]
|
||||
|
|
@ -176,7 +176,7 @@ iterator leaves[T](n: Node[T]): Node[T] =
|
|||
# XXX actually we could compute the necessary stack size in advance:
|
||||
# it's roughly log2(c.count).
|
||||
var stack = @[n]
|
||||
while stack.len > 0:
|
||||
while stack.len > 0:
|
||||
var it = stack.pop
|
||||
while not it.isLeaf:
|
||||
stack.add(it.child[1])
|
||||
|
|
@ -205,7 +205,7 @@ iterator items*[T](c: CritBitTree[T]): string =
|
|||
iterator pairs*[T](c: CritBitTree[T]): tuple[key: string, val: T] =
|
||||
## yields all (key, value)-pairs of `c`.
|
||||
for x in leaves(c.root): yield (x.key, x.val)
|
||||
|
||||
|
||||
iterator mpairs*[T](c: var CritBitTree[T]): tuple[key: string, val: var T] =
|
||||
## yields all (key, value)-pairs of `c`. The yielded values can be modified.
|
||||
for x in leaves(c.root): yield (x.key, x.val)
|
||||
|
|
@ -251,7 +251,7 @@ iterator pairsWithPrefix*[T](c: CritBitTree[T],
|
|||
## yields all (key, value)-pairs of `c` starting with `prefix`.
|
||||
let top = allprefixedAux(c, prefix)
|
||||
for x in leaves(top): yield (x.key, x.val)
|
||||
|
||||
|
||||
iterator mpairsWithPrefix*[T](c: var CritBitTree[T],
|
||||
prefix: string): tuple[key: string, val: var T] =
|
||||
## yields all (key, value)-pairs of `c` starting with `prefix`.
|
||||
|
|
|
|||
|
|
@ -27,18 +27,18 @@ type
|
|||
|
||||
SinglyLinkedList*[T] = object ## a singly linked list
|
||||
head*, tail*: SinglyLinkedNode[T]
|
||||
|
||||
|
||||
DoublyLinkedList*[T] = object ## a doubly linked list
|
||||
head*, tail*: DoublyLinkedNode[T]
|
||||
|
||||
SinglyLinkedRing*[T] = object ## a singly linked ring
|
||||
head*, tail*: SinglyLinkedNode[T]
|
||||
|
||||
|
||||
DoublyLinkedRing*[T] = object ## a doubly linked ring
|
||||
head*: DoublyLinkedNode[T]
|
||||
|
||||
{.deprecated: [TDoublyLinkedNode: DoublyLinkedNodeObj,
|
||||
PDoublyLinkedNode: DoublyLinkedNode,
|
||||
PDoublyLinkedNode: DoublyLinkedNode,
|
||||
TSinglyLinkedNode: SinglyLinkedNodeObj,
|
||||
PSinglyLinkedNode: SinglyLinkedNode,
|
||||
TDoublyLinkedList: DoublyLinkedList,
|
||||
|
|
@ -106,19 +106,19 @@ template findImpl() {.dirty.} =
|
|||
for x in nodes(L):
|
||||
if x.value == value: return x
|
||||
|
||||
iterator items*[T](L: DoublyLinkedList[T]): T =
|
||||
iterator items*[T](L: DoublyLinkedList[T]): T =
|
||||
## yields every value of `L`.
|
||||
itemsListImpl()
|
||||
|
||||
iterator items*[T](L: SinglyLinkedList[T]): T =
|
||||
iterator items*[T](L: SinglyLinkedList[T]): T =
|
||||
## yields every value of `L`.
|
||||
itemsListImpl()
|
||||
|
||||
iterator items*[T](L: SinglyLinkedRing[T]): T =
|
||||
iterator items*[T](L: SinglyLinkedRing[T]): T =
|
||||
## yields every value of `L`.
|
||||
itemsRingImpl()
|
||||
|
||||
iterator items*[T](L: DoublyLinkedRing[T]): T =
|
||||
iterator items*[T](L: DoublyLinkedRing[T]): T =
|
||||
## yields every value of `L`.
|
||||
itemsRingImpl()
|
||||
|
||||
|
|
@ -138,22 +138,22 @@ iterator mitems*[T](L: var DoublyLinkedRing[T]): var T =
|
|||
## yields every value of `L` so that you can modify it.
|
||||
itemsRingImpl()
|
||||
|
||||
iterator nodes*[T](L: SinglyLinkedList[T]): SinglyLinkedNode[T] =
|
||||
iterator nodes*[T](L: SinglyLinkedList[T]): SinglyLinkedNode[T] =
|
||||
## iterates over every node of `x`. Removing the current node from the
|
||||
## list during traversal is supported.
|
||||
nodesListImpl()
|
||||
|
||||
iterator nodes*[T](L: DoublyLinkedList[T]): DoublyLinkedNode[T] =
|
||||
iterator nodes*[T](L: DoublyLinkedList[T]): DoublyLinkedNode[T] =
|
||||
## iterates over every node of `x`. Removing the current node from the
|
||||
## list during traversal is supported.
|
||||
nodesListImpl()
|
||||
|
||||
iterator nodes*[T](L: SinglyLinkedRing[T]): SinglyLinkedNode[T] =
|
||||
iterator nodes*[T](L: SinglyLinkedRing[T]): SinglyLinkedNode[T] =
|
||||
## iterates over every node of `x`. Removing the current node from the
|
||||
## list during traversal is supported.
|
||||
nodesRingImpl()
|
||||
|
||||
iterator nodes*[T](L: DoublyLinkedRing[T]): DoublyLinkedNode[T] =
|
||||
iterator nodes*[T](L: DoublyLinkedRing[T]): DoublyLinkedNode[T] =
|
||||
## iterates over every node of `x`. Removing the current node from the
|
||||
## list during traversal is supported.
|
||||
nodesRingImpl()
|
||||
|
|
@ -165,87 +165,87 @@ template dollarImpl() {.dirty.} =
|
|||
result.add($x.value)
|
||||
result.add("]")
|
||||
|
||||
proc `$`*[T](L: SinglyLinkedList[T]): string =
|
||||
proc `$`*[T](L: SinglyLinkedList[T]): string =
|
||||
## turns a list into its string representation.
|
||||
dollarImpl()
|
||||
|
||||
proc `$`*[T](L: DoublyLinkedList[T]): string =
|
||||
proc `$`*[T](L: DoublyLinkedList[T]): string =
|
||||
## turns a list into its string representation.
|
||||
dollarImpl()
|
||||
|
||||
proc `$`*[T](L: SinglyLinkedRing[T]): string =
|
||||
proc `$`*[T](L: SinglyLinkedRing[T]): string =
|
||||
## turns a list into its string representation.
|
||||
dollarImpl()
|
||||
|
||||
proc `$`*[T](L: DoublyLinkedRing[T]): string =
|
||||
proc `$`*[T](L: DoublyLinkedRing[T]): string =
|
||||
## turns a list into its string representation.
|
||||
dollarImpl()
|
||||
|
||||
proc find*[T](L: SinglyLinkedList[T], value: T): SinglyLinkedNode[T] =
|
||||
proc find*[T](L: SinglyLinkedList[T], value: T): SinglyLinkedNode[T] =
|
||||
## searches in the list for a value. Returns nil if the value does not
|
||||
## exist.
|
||||
findImpl()
|
||||
|
||||
proc find*[T](L: DoublyLinkedList[T], value: T): DoublyLinkedNode[T] =
|
||||
proc find*[T](L: DoublyLinkedList[T], value: T): DoublyLinkedNode[T] =
|
||||
## searches in the list for a value. Returns nil if the value does not
|
||||
## exist.
|
||||
findImpl()
|
||||
|
||||
proc find*[T](L: SinglyLinkedRing[T], value: T): SinglyLinkedNode[T] =
|
||||
proc find*[T](L: SinglyLinkedRing[T], value: T): SinglyLinkedNode[T] =
|
||||
## searches in the list for a value. Returns nil if the value does not
|
||||
## exist.
|
||||
findImpl()
|
||||
|
||||
proc find*[T](L: DoublyLinkedRing[T], value: T): DoublyLinkedNode[T] =
|
||||
proc find*[T](L: DoublyLinkedRing[T], value: T): DoublyLinkedNode[T] =
|
||||
## searches in the list for a value. Returns nil if the value does not
|
||||
## exist.
|
||||
findImpl()
|
||||
|
||||
proc contains*[T](L: SinglyLinkedList[T], value: T): bool {.inline.} =
|
||||
proc contains*[T](L: SinglyLinkedList[T], value: T): bool {.inline.} =
|
||||
## searches in the list for a value. Returns false if the value does not
|
||||
## exist, true otherwise.
|
||||
result = find(L, value) != nil
|
||||
|
||||
proc contains*[T](L: DoublyLinkedList[T], value: T): bool {.inline.} =
|
||||
proc contains*[T](L: DoublyLinkedList[T], value: T): bool {.inline.} =
|
||||
## searches in the list for a value. Returns false if the value does not
|
||||
## exist, true otherwise.
|
||||
result = find(L, value) != nil
|
||||
|
||||
proc contains*[T](L: SinglyLinkedRing[T], value: T): bool {.inline.} =
|
||||
proc contains*[T](L: SinglyLinkedRing[T], value: T): bool {.inline.} =
|
||||
## searches in the list for a value. Returns false if the value does not
|
||||
## exist, true otherwise.
|
||||
result = find(L, value) != nil
|
||||
|
||||
proc contains*[T](L: DoublyLinkedRing[T], value: T): bool {.inline.} =
|
||||
proc contains*[T](L: DoublyLinkedRing[T], value: T): bool {.inline.} =
|
||||
## searches in the list for a value. Returns false if the value does not
|
||||
## exist, true otherwise.
|
||||
result = find(L, value) != nil
|
||||
|
||||
proc prepend*[T](L: var SinglyLinkedList[T],
|
||||
n: SinglyLinkedNode[T]) {.inline.} =
|
||||
proc prepend*[T](L: var SinglyLinkedList[T],
|
||||
n: SinglyLinkedNode[T]) {.inline.} =
|
||||
## prepends a node to `L`. Efficiency: O(1).
|
||||
n.next = L.head
|
||||
L.head = n
|
||||
|
||||
proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} =
|
||||
proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} =
|
||||
## prepends a node to `L`. Efficiency: O(1).
|
||||
prepend(L, newSinglyLinkedNode(value))
|
||||
|
||||
proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
|
||||
|
||||
proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
|
||||
## appends a node `n` to `L`. Efficiency: O(1).
|
||||
n.next = nil
|
||||
n.prev = L.tail
|
||||
if L.tail != nil:
|
||||
if L.tail != nil:
|
||||
assert(L.tail.next == nil)
|
||||
L.tail.next = n
|
||||
L.tail = n
|
||||
if L.head == nil: L.head = n
|
||||
|
||||
proc append*[T](L: var DoublyLinkedList[T], value: T) =
|
||||
proc append*[T](L: var DoublyLinkedList[T], value: T) =
|
||||
## appends a value to `L`. Efficiency: O(1).
|
||||
append(L, newDoublyLinkedNode(value))
|
||||
|
||||
proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
|
||||
proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
|
||||
## prepends a node `n` to `L`. Efficiency: O(1).
|
||||
n.prev = nil
|
||||
n.next = L.head
|
||||
|
|
@ -255,11 +255,11 @@ proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
|
|||
L.head = n
|
||||
if L.tail == nil: L.tail = n
|
||||
|
||||
proc prepend*[T](L: var DoublyLinkedList[T], value: T) =
|
||||
proc prepend*[T](L: var DoublyLinkedList[T], value: T) =
|
||||
## prepends a value to `L`. Efficiency: O(1).
|
||||
prepend(L, newDoublyLinkedNode(value))
|
||||
|
||||
proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
|
||||
|
||||
proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
|
||||
## removes `n` from `L`. Efficiency: O(1).
|
||||
if n == L.tail: L.tail = n.prev
|
||||
if n == L.head: L.head = n.next
|
||||
|
|
@ -267,7 +267,7 @@ proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
|
|||
if n.prev != nil: n.prev.next = n.next
|
||||
|
||||
|
||||
proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
|
||||
proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
|
||||
## appends a node `n` to `L`. Efficiency: O(1).
|
||||
if L.head != nil:
|
||||
n.next = L.head
|
||||
|
|
@ -279,11 +279,11 @@ proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
|
|||
L.head = n
|
||||
L.tail = n
|
||||
|
||||
proc append*[T](L: var SinglyLinkedRing[T], value: T) =
|
||||
proc append*[T](L: var SinglyLinkedRing[T], value: T) =
|
||||
## appends a value to `L`. Efficiency: O(1).
|
||||
append(L, newSinglyLinkedNode(value))
|
||||
|
||||
proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
|
||||
proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
|
||||
## prepends a node `n` to `L`. Efficiency: O(1).
|
||||
if L.head != nil:
|
||||
n.next = L.head
|
||||
|
|
@ -294,11 +294,11 @@ proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
|
|||
L.tail = n
|
||||
L.head = n
|
||||
|
||||
proc prepend*[T](L: var SinglyLinkedRing[T], value: T) =
|
||||
proc prepend*[T](L: var SinglyLinkedRing[T], value: T) =
|
||||
## prepends a value to `L`. Efficiency: O(1).
|
||||
prepend(L, newSinglyLinkedNode(value))
|
||||
|
||||
proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
|
||||
proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
|
||||
## appends a node `n` to `L`. Efficiency: O(1).
|
||||
if L.head != nil:
|
||||
n.next = L.head
|
||||
|
|
@ -310,13 +310,13 @@ proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
|
|||
n.next = n
|
||||
L.head = n
|
||||
|
||||
proc append*[T](L: var DoublyLinkedRing[T], value: T) =
|
||||
proc append*[T](L: var DoublyLinkedRing[T], value: T) =
|
||||
## appends a value to `L`. Efficiency: O(1).
|
||||
append(L, newDoublyLinkedNode(value))
|
||||
|
||||
proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
|
||||
proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
|
||||
## prepends a node `n` to `L`. Efficiency: O(1).
|
||||
if L.head != nil:
|
||||
if L.head != nil:
|
||||
n.next = L.head
|
||||
n.prev = L.head.prev
|
||||
L.head.prev.next = n
|
||||
|
|
@ -326,17 +326,17 @@ proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
|
|||
n.next = n
|
||||
L.head = n
|
||||
|
||||
proc prepend*[T](L: var DoublyLinkedRing[T], value: T) =
|
||||
proc prepend*[T](L: var DoublyLinkedRing[T], value: T) =
|
||||
## prepends a value to `L`. Efficiency: O(1).
|
||||
prepend(L, newDoublyLinkedNode(value))
|
||||
|
||||
proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
|
||||
|
||||
proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
|
||||
## removes `n` from `L`. Efficiency: O(1).
|
||||
n.next.prev = n.prev
|
||||
n.prev.next = n.next
|
||||
if n == L.head:
|
||||
if n == L.head:
|
||||
var p = L.head.prev
|
||||
if p == L.head:
|
||||
if p == L.head:
|
||||
# only one element left:
|
||||
L.head = nil
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ proc dequeue*[T](q: var Queue[T]): T =
|
|||
result = q.data[q.rd]
|
||||
q.rd = (q.rd + 1) and q.mask
|
||||
|
||||
proc `$`*[T](q: Queue[T]): string =
|
||||
proc `$`*[T](q: Queue[T]): string =
|
||||
## turns a queue into its string representation.
|
||||
result = "["
|
||||
for x in items(q):
|
||||
|
|
@ -95,7 +95,7 @@ when isMainModule:
|
|||
q.add(6)
|
||||
var second = q.dequeue
|
||||
q.add(789)
|
||||
|
||||
|
||||
assert first == 123
|
||||
assert second == 9
|
||||
assert($q == "[4, 56, 6, 789]")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue