make oids module better (#16704)

* make oids modules better

* Update lib/pure/oids.nim

* fix
This commit is contained in:
flywind
2021-01-25 00:39:25 -06:00
committed by GitHub
parent d99ea00829
commit 8d3e0c7b9b
2 changed files with 45 additions and 26 deletions

View File

@@ -13,9 +13,10 @@
## from the Mongodb interface and it thus binary compatible with a Mongo OID.
##
## This implementation calls `initRand()` for the first call of
## ``genOid``.
## `genOid`.
import hashes, times, endians, random
import std/[hashes, times, endians, random]
from std/private/decode_helpers import handleHexChar
type
Oid* = object ## An OID.
@@ -23,9 +24,9 @@ type
fuzz: int32 ##
count: int32 ##
proc `==`*(oid1: Oid, oid2: Oid): bool =
proc `==`*(oid1: Oid, oid2: Oid): bool {.inline.} =
## Compares two Mongo Object IDs for equality.
return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and
result = (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and
(oid1.count == oid2.count)
proc hash*(oid: Oid): Hash =
@@ -36,12 +37,8 @@ proc hash*(oid: Oid): Hash =
h = h !& hash(oid.count)
result = !$h
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: discard
proc hexbyte*(hex: char): int {.inline.} =
result = handleHexChar(hex)
proc parseOid*(str: cstring): Oid =
## Parses an OID.
@@ -51,45 +48,60 @@ proc parseOid*(str: cstring): Oid =
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.
template toStringImpl[T: string | cstring](result: var T, oid: Oid) =
## Stringifies `oid`.
const hex = "0123456789abcdef"
# work around a compiler bug:
var str = str
const N = 24
when T is string:
result.setLen N
var o = oid
var bytes = cast[cstring](addr(o))
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'
when T is cstring:
result[N] = '\0'
proc oidToString*(oid: Oid, str: cstring) {.deprecated: "unsafe; use `$`".} =
## Converts an oid to `str` which must have space allocated for 25 elements.
# work around a compiler bug:
var str = str
toStringImpl(str, oid)
proc `$`*(oid: Oid): string =
## Converts an oid to string.
result = newString(24)
oidToString(oid, result)
toStringImpl(result, oid)
let
t = getTime().toUnix.int32
var
t = getTime().toUnix.int32
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.int32
var i = cast[int32](atomicInc(incr))
bigEndian32(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
if false: doAssert $genOid() == "5fc7f546ddbbc84800006aaf"
t = getTime().toUnix.int32
var i = cast[int32](atomicInc(incr))
bigEndian32(addr result.time, addr(t))
result.fuzz = fuzz
bigEndian32(addr result.count, addr(i))
genOid(result, incr, fuzz)
proc generatedTime*(oid: Oid): Time =
## Returns the generated timestamp of the OID.

View File

@@ -21,6 +21,13 @@ proc handleHexChar*(c: char, x: var int): bool {.inline.} =
else:
result = false
proc handleHexChar*(c: char): int {.inline.} =
case c
of '0'..'9': result = (ord(c) - ord('0'))
of 'a'..'f': result = (ord(c) - ord('a') + 10)
of 'A'..'F': result = (ord(c) - ord('A') + 10)
else: discard
proc decodePercent*(s: openArray[char], i: var int): char =
## Converts `%xx` hexadecimal to the character with ordinal number `xx`.
##