Last active
August 29, 2015 14:24
-
-
Save fowlmouth/74d53453aff4fc057b1f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import strutils,times | |
import unsigned | |
type | |
UIDT* = uint64 | |
UID* = distinct UIDT | |
proc sh (s: UID|UIDT|uint8): string = | |
"0x"& | |
toUpper(toHex(s.BiggestInt, sizeof(s)*2)) | |
type | |
IDgen = object | |
epoch: Time | |
idCount: int8 | |
ids: array[8,(uint8,uint8)] | |
idState: uint64 # array[8,uint64] | |
prepNext*: proc(id:var IDgen) | |
template idSize* (g:IDgen; st:SomeInteger): uint8 = | |
g.ids[st][0] | |
template idOffs* (g:IDgen; st:SomeInteger): uint8 = | |
g.ids[st][1] | |
template maskBits(x:expr): expr = | |
not(not(0u64) shl x.uint64) | |
template maskComponent (g:IDgen; st:SomeInteger): uint64 = | |
maskBits(g.idSize(st)) shl g.idOffs(st) | |
proc validState* (g:IDgen; st:int; val:uint64): bool = | |
(val and not maskBits(g.idSize(st))) == 0 | |
proc setState* (g:IDgen; st:int; val:uint64; id:UIDT): (bool,UIDT) = | |
result[0] = g.validState(st,val) | |
if not result[0]: return | |
let offs = g.idOffs(st).uint64 | |
result[1] = (id and not(g.maskComponent(st))) | |
result[1] = result[1] or | |
(val shl offs) | |
proc setState* (g:var IDgen; st:int; val:uint64): bool = | |
let (has,res) = g.setState(st,val, g.idState) | |
if has: | |
g.idState = res | |
return true | |
proc getState* (g:IDgen; st:int; id:UIDT): uint64 = | |
let offs = g.idOffs(st).uint64 | |
result = | |
(id shr offs) and maskBits(g.idSize(st)) | |
proc getState* (g:var IDgen; st:int): uint64 = | |
g.getState(st, g.idState) | |
proc initGen* (idSizes: openarray[int8]; epoch = getTime()): IDgen = | |
assert idSizes.len > 0 | |
assert idSizes.len < 9 | |
result.epoch = epoch | |
result.idCount = idSizes.len.int8 | |
var bits = 0 | |
for idx,i in idSizes.pairs: | |
assert i > 0 | |
assert bits < 64 | |
result.idSize(idx) = i.uint8 | |
result.idOffs(idx) = bits.uint8 | |
bits += i.int | |
# if bits > 64: | |
# raise newException(EIO, "too many bits "& $bits) | |
proc next* (g: var IDgen): UID = | |
g.prepNext(g) | |
result = g.idState.UID | |
#echo "next: ", sh(result) | |
proc showState* (g:var IDgen) = | |
for i in 0 .. < g.idCount: | |
echo "reg ", i, " = ", g.getState(i) | |
echo " ", sh(maskBits(g.idSize(i)) shl g.idOffs(i)), | |
" (", sh(g.getState(i) shl g.idOffs(i)), ")" | |
discard | |
proc breakdown* (g:var IDgen; id:UID): seq[UIDT] = | |
newSeq result, g.idCount | |
for idx in 0 .. < g.idCount: | |
result[idx] = g.getState(idx, id.UIDT) | |
when isMainModule: | |
import os | |
var basicflake_layout = | |
@[16i8, 16i8, 32i8] | |
let | |
counter_state = 0 | |
machine_id_state = 1 | |
timestamp_state = 2 | |
var basicflake = initGen(basicflake_layout) | |
# middle state used for worker ID | |
assert basicflake.idSize(counter_state) == 16 | |
assert basicflake.idSize(machine_id_state) == 16 | |
assert basicflake.idSize(timestamp_state) == 32 | |
assert basicflake.idOffs(counter_state) == 0 | |
assert basicflake.idOffs(machine_id_state) == 16 | |
assert basicflake.idOffs(timestamp_state) == 32 | |
echo sh(basicflake.maskComponent(counter_state)) | |
echo sh(basicflake.maskComponent(1)) | |
echo sh(basicflake.maskComponent(timestamp_state)) | |
assert basicflake.setState(machine_id_state, 15) | |
basicflake.showState | |
echo "---" | |
# setup its tick function | |
basicflake.prepNext = proc(g: var IDgen) = | |
let t = uint64(getTime() - g.epoch) | |
echo t | |
if t != g.getState(timestamp_state): | |
# reset the counter | |
assert g.setState(counter_state,0) | |
assert g.setState(timestamp_state,t) | |
else: | |
assert g.setState(counter_state, g.getState(counter_state) + 1) | |
var ids: seq[UID] | |
ids = @[] | |
for i in 0 .. <30: | |
if i mod 7 == 0: | |
sleep 850 | |
let id = basicflake.next | |
ids.add id | |
for id in ids: | |
echo basicflake.breakdown(id) | |
echo sizeof IDgen |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment