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:
flywind 2021-01-07 02:38:31 -06:00 • committed by GitHub
commit 89a21e4ec7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 25 additions and 20 deletions

View file

@ -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
View file

@ -0,0 +1,6 @@
import std/oids
block: # genOid
let x = genOid()
doAssert ($x).len == 24