unit kern_id; {$mode ObjFPC}{$H+} {$CALLING SysV_ABI_CDecl} interface uses hamt, kern_rwlock; Const def_max_key=$7FFFFFFF; type p_id_desc=^t_id_desc; t_id_desc=packed record refs:QWORD; free:procedure(data:pointer); end; p_id_desc_table=^t_id_desc_table; t_id_desc_table=packed record FLock :Pointer; FHAMT :TSTUB_HAMT32; FCount :Integer; FPos :Integer; min_key:Integer; max_key:Integer; end; Procedure id_acqure (d:p_id_desc); Procedure id_release(d:p_id_desc); procedure id_table_init(t:p_id_desc_table;min:Integer); procedure id_table_fini(t:p_id_desc_table); function id_new(t:p_id_desc_table;d:p_id_desc;pKey:PInteger):Boolean; function id_set(t:p_id_desc_table;d:p_id_desc;Key:Integer;old:PPointer):Boolean; function id_get(t:p_id_desc_table;Key:Integer):p_id_desc; function id_del(t:p_id_desc_table;Key:Integer;old:PPointer):Boolean; implementation Procedure id_acqure(d:p_id_desc); begin if (d=nil) then Exit; System.InterlockedIncrement64(d^.refs); end; Procedure id_release(d:p_id_desc); begin if (d=nil) then Exit; if (System.InterlockedDecrement64(d^.refs)=0) then if (d^.free<>nil) then begin d^.free(d); end; end; procedure _free_data_cb(data,userdata:Pointer); register; begin if (data<>nil) then begin id_release(data); end; end; procedure id_table_init(t:p_id_desc_table;min:Integer); begin if (t=nil) then Exit; FillChar(t^,SizeOf(t_id_desc_table),0); t^.min_key:=min; t^.max_key:=def_max_key; t^.FPos :=min; end; procedure id_table_fini(t:p_id_desc_table); begin if (t=nil) then Exit; HAMT_clear32(@t^.FHAMT,@_free_data_cb,nil); end; function id_new(t:p_id_desc_table;d:p_id_desc;pKey:PInteger):Boolean; Label _data,_exit; Var i,m:Integer; data:PPointer; begin Result:=False; if (t=nil) or (pKey=nil) then Exit; rw_wlock(t^.FLock); m:=(t^.max_key-t^.min_key); if (t^.FCount>=m+1) then goto _exit; if (t^.FPost^.max_key) then begin t^.FPos:=t^.min_key; end; if (t^.FCount=0) then begin pKey^:=t^.FPos; Inc(t^.FPos); data:=HAMT_insert32(@t^.FHAMT,pKey^,Pointer(d)); if (data=nil) then goto _exit; if (data^<>Pointer(d)) then goto _exit; end else begin For i:=0 to m do begin pKey^:=t^.FPos; Inc(t^.FPos); if (t^.FPos>t^.max_key) then begin t^.FPos:=t^.min_key; end; data:=HAMT_insert32(@t^.FHAMT,pKey^,Pointer(d)); if (data=nil) then goto _exit; if (data^=Pointer(d)) then goto _data; end; goto _exit; end; _data: Inc(t^.FCount); id_acqure(d); id_acqure(d); Result:=True; _exit: rw_wunlock(t^.FLock); end; function id_set(t:p_id_desc_table;d:p_id_desc;Key:Integer;old:PPointer):Boolean; Label _exit; Var data:PPointer; begin Result:=False; if (t=nil) or (Keyt^.max_key) then Exit; rw_wlock(t^.FLock); data:=HAMT_insert32(@t^.FHAMT,Key,Pointer(d)); if (data=nil) then goto _exit; if (data^<>Pointer(d)) then begin if (old<>nil) then begin old^:=data^; data^:=Pointer(d); end else begin goto _exit; end; end else if (old<>nil) then begin old^:=nil; end; id_acqure(d); Result:=True; _exit: rw_wunlock(t^.FLock); end; function id_get(t:p_id_desc_table;Key:Integer):p_id_desc; Var data:PPointer; Label _exit; begin Result:=nil; if (t=nil) or (Keyt^.max_key) then Exit; rw_rlock(t^.FLock); data:=HAMT_search32(@t^.FHAMT,Key); if (data=nil) then Goto _exit; Pointer(Result):=data^; id_acqure(Result); _exit: rw_runlock(t^.FLock); end; function id_del(t:p_id_desc_table;Key:Integer;old:PPointer):Boolean; Var d:p_id_desc; begin Result:=False; if (t=nil) or (Keyt^.max_key) then Exit; d:=nil; rw_wlock(t^.FLock); if HAMT_delete32(@t^.FHAMT,Key,@d) then begin if (old<>nil) then begin old^:=d; end else begin id_release(d); end; Dec(t^.FCount); Result:=True; end else if (old<>nil) then begin old^:=nil; end; rw_wunlock(t^.FLock); end; end.