Skip to content

Commit

Permalink
oids: switch from PRNG to random module (#16203)
Browse files Browse the repository at this point in the history
* switch from PRNG to random module
* fix the regression
* comments + tests
* runnableExamples
* make oids better
  • Loading branch information
ringabout authored Jan 7, 2021
1 parent bab0aa6 commit 89a21e4
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 20 deletions.
39 changes: 19 additions & 20 deletions lib/pure/oids.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,24 @@
## produce a globally distributed unique ID. This implementation was extracted
## 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``.

import hashes, times, endians
import hashes, times, endians, random

type
Oid* = object ## an OID
Oid* = object ## An OID.
time: int32 ##
fuzz: int32 ##
count: int32 ##

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
(oid1.count == oid2.count)

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
h = h !& hash(oid.time)
h = h !& hash(oid.fuzz)
Expand All @@ -44,14 +44,15 @@ proc hexbyte*(hex: char): int =
else: discard

proc parseOid*(str: cstring): Oid =
## parses an OID.
## Parses an OID.
var bytes = cast[cstring](addr(result.time))
var i = 0
while i < 12:
bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1]))
inc(i)

proc oidToString*(oid: Oid, str: cstring) =
## Converts an oid to `str` which must have space allocated for 25 elements.
const hex = "0123456789abcdef"
# work around a compiler bug:
var str = str
Expand All @@ -66,35 +67,33 @@ proc oidToString*(oid: Oid, str: cstring) =
str[24] = '\0'

proc `$`*(oid: Oid): string =
## Converts an oid to string.
result = newString(24)
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
incr: int = rand()
fuzz: int32 = rand()
t = getTime().toUnix.int32
seed = initRand(t)
incr: int = seed.rand(int.high)

let fuzz = cast[int32](seed.rand(high(int)))

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
var i = int32(atomicInc(incr))
var i = cast[int32](atomicInc(incr))

bigEndian32(addr result.time, addr(t))
result.fuzz = fuzz
bigEndian32(addr result.count, addr(i))

proc generatedTime*(oid: Oid): Time =
## returns the generated timestamp of the OID.
## Returns the generated timestamp of the OID.
var tmp: int32
var dummy = oid.time
bigEndian32(addr(tmp), addr(dummy))
result = fromUnix(tmp)

when not defined(testing) and isMainModule:
let xo = genOid()
echo xo.generatedTime
6 changes: 6 additions & 0 deletions tests/stdlib/toids.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import std/oids


block: # genOid
let x = genOid()
doAssert ($x).len == 24

0 comments on commit 89a21e4

Please sign in to comment.