diff options
Diffstat (limited to 'lib/pure/oids.nim')
-rw-r--r-- | lib/pure/oids.nim | 130 |
1 files changed, 71 insertions, 59 deletions
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index 0fd1d8cd2..4d6ceefd7 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -1,87 +1,99 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2012 Andreas Rumpf +# Nim's Runtime Library +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Nimrod OID support. An OID is a global ID that consists of a timestamp, -## a unique counter and a random value. This combination should suffice to -## produce a globally distributed unique ID. This implementation was extracted -## from the Mongodb interface and it thus binary compatible with a Mongo OID. +## Nim OID support. An OID is a global ID that consists of a timestamp, +## a unique counter and a random value. This combination should suffice to +## produce a globally distributed unique ID. ## -## This implementation calls ``math.randomize()`` for the first call of -## ``genOid``. +## This implementation calls `initRand()` for the first call of +## `genOid`. -import times, endians +import std/[hashes, times, endians, random] +from std/private/decode_helpers import handleHexChar + +when defined(nimPreviewSlimSystem): + import std/sysatomics type - Toid* {.pure, final.} = object ## an OID - time: int32 ## - fuzz: int32 ## - count: int32 ## - -proc hexbyte*(hex: char): int = - case hex - of '0'..'9': result = (ord(hex) - ord('0')) - of 'a'..'f': result = (ord(hex) - ord('a') + 10) - of 'A'..'F': result = (ord(hex) - ord('A') + 10) - else: nil - -proc parseOid*(str: cstring): TOid = - ## parses an OID. - var bytes = cast[cstring](addr(result.time)) + Oid* = object ## An OID. + time: int64 + fuzz: int32 + count: int32 + +proc `==`*(oid1: Oid, oid2: Oid): bool {.inline.} = + ## Compares two OIDs for equality. + result = (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and + (oid1.count == oid2.count) + +proc hash*(oid: Oid): Hash = + ## Generates the hash of an OID for use in hashtables. + var h: Hash = 0 + h = h !& hash(oid.time) + h = h !& hash(oid.fuzz) + h = h !& hash(oid.count) + result = !$h + +proc hexbyte*(hex: char): int {.inline.} = + result = handleHexChar(hex) + +proc parseOid*(str: cstring): Oid = + ## Parses an OID. + var bytes = cast[cstring](cast[pointer](cast[int](addr(result.time)) + 4)) 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: TOid, str: cstring) = +proc `$`*(oid: Oid): string = + ## Converts an OID to a string. const hex = "0123456789abcdef" - # work around a compiler bug: - var str = str + + result.setLen 24 + var o = oid - var bytes = cast[cstring](addr(o)) + var bytes = cast[cstring](cast[pointer](cast[int](addr(o)) + 4)) var i = 0 while i < 12: let b = bytes[i].ord - str[2 * i] = hex[(b and 0xF0) shr 4] - str[2 * i + 1] = hex[b and 0xF] + result[2 * i] = hex[(b and 0xF0) shr 4] + result[2 * i + 1] = hex[b and 0xF] inc(i) - str[24] = '\0' + +let + t = getTime().toUnix var - incr: int - fuzz: int32 - -proc genOid*(): TOid = - ## generates a new OID. - proc rand(): cint {.importc: "rand", nodecl.} - proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".} - proc srand(seed: cint) {.importc: "srand", nodecl.} - - var t = gettime(nil) - - var i = int32(incr) - atomicInc(incr) - - if fuzz == 0: - # racy, but fine semantically: - srand(t) - fuzz = rand() - bigEndian32(addr result.time, addr(t)) + seed = initRand(t) + incr: int = seed.rand(int.high) + +let fuzz = cast[int32](seed.rand(high(int))) + + +template genOid(result: var Oid, incr: var int, fuzz: int32) = + var time = getTime().toUnix + var i = cast[int32](atomicInc(incr)) + + bigEndian64(addr result.time, addr(time)) result.fuzz = fuzz bigEndian32(addr result.count, addr(i)) -proc generatedTime*(oid: TOid): TTime = - ## returns the generated timestamp of the OID. - var tmp: int32 - var dummy = oid.time - bigEndian32(addr(tmp), addr(dummy)) - result = TTime(tmp) +proc genOid*(): Oid = + ## Generates a new OID. + runnableExamples: + doAssert ($genOid()).len == 24 + runnableExamples("-r:off"): + echo $genOid() # for example, "5fc7f546ddbbc84800006aaf" + genOid(result, incr, fuzz) -when isMainModule: - let xo = genOID() - echo xo.generatedTime +proc generatedTime*(oid: Oid): Time = + ## Returns the generated timestamp of the OID. + var tmp: int64 + var dummy = oid.time + bigEndian64(addr(tmp), addr(dummy)) + result = fromUnix(tmp) |