summary refs log tree commit diff stats
path: root/lib/pure/oids.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/oids.nim')
-rw-r--r--lib/pure/oids.nim130
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)