diff options
Diffstat (limited to 'lib/pure/oids.nim')
-rw-r--r-- | lib/pure/oids.nim | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim new file mode 100644 index 000000000..4d6ceefd7 --- /dev/null +++ b/lib/pure/oids.nim @@ -0,0 +1,99 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2013 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## 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 `initRand()` for the first call of +## `genOid`. + +import std/[hashes, times, endians, random] +from std/private/decode_helpers import handleHexChar + +when defined(nimPreviewSlimSystem): + import std/sysatomics + +type + 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 `$`*(oid: Oid): string = + ## Converts an OID to a string. + const hex = "0123456789abcdef" + + result.setLen 24 + + var o = oid + var bytes = cast[cstring](cast[pointer](cast[int](addr(o)) + 4)) + var i = 0 + while i < 12: + let b = bytes[i].ord + result[2 * i] = hex[(b and 0xF0) shr 4] + result[2 * i + 1] = hex[b and 0xF] + inc(i) + +let + t = getTime().toUnix + +var + 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 genOid*(): Oid = + ## Generates a new OID. + runnableExamples: + doAssert ($genOid()).len == 24 + runnableExamples("-r:off"): + echo $genOid() # for example, "5fc7f546ddbbc84800006aaf" + genOid(result, incr, fuzz) + +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) |