oids: switch from PRNG to random module (#16203)
* switch from PRNG to random module * fix the regression * comments + tests * runnableExamples * make oids better
This commit is contained in:
parent
bab0aa6ecf
commit
89a21e4ec7
2 changed files with 25 additions and 20 deletions
|
|
@ -12,24 +12,24 @@
|
||||||
## produce a globally distributed unique ID. This implementation was extracted
|
## produce a globally distributed unique ID. This implementation was extracted
|
||||||
## from the Mongodb interface and it thus binary compatible with a Mongo OID.
|
## from the Mongodb interface and it thus binary compatible with a Mongo OID.
|
||||||
##
|
##
|
||||||
## This implementation calls ``math.randomize()`` for the first call of
|
## This implementation calls `initRand()` for the first call of
|
||||||
## ``genOid``.
|
## ``genOid``.
|
||||||
|
|
||||||
import hashes, times, endians
|
import hashes, times, endians, random
|
||||||
|
|
||||||
type
|
type
|
||||||
Oid* = object ## an OID
|
Oid* = object ## An OID.
|
||||||
time: int32 ##
|
time: int32 ##
|
||||||
fuzz: int32 ##
|
fuzz: int32 ##
|
||||||
count: int32 ##
|
count: int32 ##
|
||||||
|
|
||||||
proc `==`*(oid1: Oid, oid2: Oid): bool =
|
proc `==`*(oid1: Oid, oid2: Oid): bool =
|
||||||
## Compare two Mongo Object IDs for equality
|
## Compares two Mongo Object IDs for equality.
|
||||||
return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and
|
return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and
|
||||||
(oid1.count == oid2.count)
|
(oid1.count == oid2.count)
|
||||||
|
|
||||||
proc hash*(oid: Oid): Hash =
|
proc hash*(oid: Oid): Hash =
|
||||||
## Generate hash of Oid for use in hashtables
|
## Generates hash of Oid for use in hashtables.
|
||||||
var h: Hash = 0
|
var h: Hash = 0
|
||||||
h = h !& hash(oid.time)
|
h = h !& hash(oid.time)
|
||||||
h = h !& hash(oid.fuzz)
|
h = h !& hash(oid.fuzz)
|
||||||
|
|
@ -44,7 +44,7 @@ proc hexbyte*(hex: char): int =
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc parseOid*(str: cstring): Oid =
|
proc parseOid*(str: cstring): Oid =
|
||||||
## parses an OID.
|
## Parses an OID.
|
||||||
var bytes = cast[cstring](addr(result.time))
|
var bytes = cast[cstring](addr(result.time))
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < 12:
|
while i < 12:
|
||||||
|
|
@ -52,6 +52,7 @@ proc parseOid*(str: cstring): Oid =
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
proc oidToString*(oid: Oid, str: cstring) =
|
proc oidToString*(oid: Oid, str: cstring) =
|
||||||
|
## Converts an oid to `str` which must have space allocated for 25 elements.
|
||||||
const hex = "0123456789abcdef"
|
const hex = "0123456789abcdef"
|
||||||
# work around a compiler bug:
|
# work around a compiler bug:
|
||||||
var str = str
|
var str = str
|
||||||
|
|
@ -66,35 +67,33 @@ proc oidToString*(oid: Oid, str: cstring) =
|
||||||
str[24] = '\0'
|
str[24] = '\0'
|
||||||
|
|
||||||
proc `$`*(oid: Oid): string =
|
proc `$`*(oid: Oid): string =
|
||||||
|
## Converts an oid to string.
|
||||||
result = newString(24)
|
result = newString(24)
|
||||||
oidToString(oid, result)
|
oidToString(oid, result)
|
||||||
|
|
||||||
proc rand(): cint {.importc: "rand", header: "<stdlib.h>", nodecl.}
|
|
||||||
proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>", nodecl.}
|
|
||||||
|
|
||||||
var t = getTime().toUnix.int32
|
|
||||||
srand(t)
|
|
||||||
|
|
||||||
var
|
var
|
||||||
incr: int = rand()
|
t = getTime().toUnix.int32
|
||||||
fuzz: int32 = rand()
|
seed = initRand(t)
|
||||||
|
incr: int = seed.rand(int.high)
|
||||||
|
|
||||||
|
let fuzz = cast[int32](seed.rand(high(int)))
|
||||||
|
|
||||||
proc genOid*(): Oid =
|
proc genOid*(): Oid =
|
||||||
## generates a new OID.
|
## Generates a new OID.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert ($genOid()).len == 24
|
||||||
|
if false: doAssert $genOid() == "5fc7f546ddbbc84800006aaf"
|
||||||
t = getTime().toUnix.int32
|
t = getTime().toUnix.int32
|
||||||
var i = int32(atomicInc(incr))
|
var i = cast[int32](atomicInc(incr))
|
||||||
|
|
||||||
bigEndian32(addr result.time, addr(t))
|
bigEndian32(addr result.time, addr(t))
|
||||||
result.fuzz = fuzz
|
result.fuzz = fuzz
|
||||||
bigEndian32(addr result.count, addr(i))
|
bigEndian32(addr result.count, addr(i))
|
||||||
|
|
||||||
proc generatedTime*(oid: Oid): Time =
|
proc generatedTime*(oid: Oid): Time =
|
||||||
## returns the generated timestamp of the OID.
|
## Returns the generated timestamp of the OID.
|
||||||
var tmp: int32
|
var tmp: int32
|
||||||
var dummy = oid.time
|
var dummy = oid.time
|
||||||
bigEndian32(addr(tmp), addr(dummy))
|
bigEndian32(addr(tmp), addr(dummy))
|
||||||
result = fromUnix(tmp)
|
result = fromUnix(tmp)
|
||||||
|
|
||||||
when not defined(testing) and isMainModule:
|
|
||||||
let xo = genOid()
|
|
||||||
echo xo.generatedTime
|
|
||||||
|
|
|
||||||
6
tests/stdlib/toids.nim
Normal file
6
tests/stdlib/toids.nim
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import std/oids
|
||||||
|
|
||||||
|
|
||||||
|
block: # genOid
|
||||||
|
let x = genOid()
|
||||||
|
doAssert ($x).len == 24
|
||||||
Loading…
Add table
Add a link
Reference in a new issue