55
56
%% Define a hashtable. The default values are the standard ones.
57
{size=0 ::integer(), % Number of elements
58
n=?seg_size ::integer(), % Number of active slots
59
maxn=?seg_size ::integer(), % Maximum slots
60
bso=?seg_size div 2 ::integer(), % Buddy slot offset
61
exp_size=?exp_size ::integer(), % Size to expand at
62
con_size=?con_size ::integer(), % Size to contract at
63
empty, % Empty segment
64
segs ::tuple() % Segments
58
{size=0 :: non_neg_integer(), % Number of elements
59
n=?seg_size :: non_neg_integer(), % Number of active slots
60
maxn=?seg_size :: non_neg_integer(), % Maximum slots
61
bso=?seg_size div 2 :: non_neg_integer(), % Buddy slot offset
62
exp_size=?exp_size :: non_neg_integer(), % Size to expand at
63
con_size=?con_size :: non_neg_integer(), % Size to contract at
64
empty :: tuple(), % Empty segment
65
segs :: tuple() % Segments
67
%% A declaration equivalent to the following one is hard-coded in erl_types.
68
%% That declaration contains hard-coded information about the #dict{}
69
%% structure and the types of its fields. So, please make sure that any
70
%% changes to its structure are also propagated to erl_types.erl.
72
%% -opaque dict() :: #dict{}.
67
74
-define(kv(K,V), [K|V]). % Key-Value pair format
68
75
%%-define(kv(K,V), {K,V}). % Key-Value pair format
77
-spec new() -> dict().
73
80
Empty = mk_seg(?seg_size),
74
81
#dict{empty=Empty,segs={Empty}}.
76
%% is_key(Key, Dictionary) -> bool().
83
-spec is_key(term(), dict()) -> bool().
79
86
Slot = get_slot(D, Key),
84
91
find_key(K, [_|Bkt]) -> find_key(K, Bkt);
85
92
find_key(_, []) -> false.
87
%% to_list(Dictionary) -> [{Key,Value}].
94
-spec to_list(dict()) -> [{term(), term()}].
90
97
fold(fun (Key, Val, List) -> [{Key,Val}|List] end, [], D).
92
%% from_list([{Key,Value}]) -> Dictionary.
99
-spec from_list([{term(), term()}]) -> dict().
95
102
lists:foldl(fun ({K,V}, D) -> store(K, V, D) end, new(), L).
97
%% size(Dictionary) -> integer().
104
-spec size(dict()) -> non_neg_integer().
99
106
size(#dict{size=N}) when is_integer(N), N >= 0 -> N.
101
%% fetch(Key, Dictionary) -> Value.
108
-spec fetch(term(), dict()) -> term().
104
111
Slot = get_slot(D, Key),
105
112
Bkt = get_bucket(D, Slot),
113
try fetch_val(Key, Bkt)
115
badarg -> erlang:error(badarg, [Key, D])
108
118
fetch_val(K, [?kv(K,Val)|_]) -> Val;
109
fetch_val(K, [_|Bkt]) -> fetch_val(K, Bkt).
119
fetch_val(K, [_|Bkt]) -> fetch_val(K, Bkt);
120
fetch_val(_, []) -> throw(badarg).
111
%% find(Key, Dictionary) -> {ok,Value} | error.
122
-spec find(term(), dict()) -> {'ok', term()} | 'error'.
114
125
Slot = get_slot(D, Key),
187
198
{[Other|Bkt1],Ic};
188
199
app_list_bkt(Key, L, []) -> {[?kv(Key,L)],1}.
190
% %% first_key(Table) -> {ok,Key} | error.
191
% %% Find the "first" key in a Table.
194
% case next_bucket(T, 1) of
195
% [?kv(K,Val)|Bkt] -> {ok,K};
196
% [] -> error %No elements
199
% next_bucket(T, Slot) when Slot > T#dict.n -> [];
200
% next_bucket(T, Slot) ->
201
% case get_bucket(T, Slot) of
202
% [] -> next_bucket(T, Slot+1); %Empty bucket
206
%% next_key(Table, Key) -> {ok,NextKey} | error.
208
% next_key(T, Key) ->
209
% Slot = get_slot(T, Key),
210
% B = get_bucket(T, Slot),
211
% %% Find a bucket with something in it.
212
% Bkt = case bucket_after_key(Key, B) of
213
% no_key -> exit(badarg);
214
% [] -> next_bucket(T, Slot+1);
218
% [?kv(Next,Val)|_] -> {ok,Next};
219
% [] -> error %We have reached the end!
222
% bucket_after_key(Key, [?kv(Key,Val)|Bkt]) -> Bkt;
223
% bucket_after_key(Key, [Other|Bkt]) ->
224
% bucket_after_key(Key, Bkt);
225
% bucket_after_key(Key, []) -> no_key. %Key not found!
227
%% on_key(Fun, Key, Dictionary) -> Dictionary.
229
% on_key(F, Key, D0) ->
230
% Slot = get_slot(D0, Key),
231
% {D1,Dc} = on_bucket(fun (B0) -> on_key_bkt(Key, F, B0) end,
233
% maybe_contract(D1, Dc).
235
% on_key_bkt(Key, F, [?kv(Key,Val)|Bkt]) ->
237
% {ok,New} -> {[?kv(Key,New)|Bkt],0};
240
% on_key_bkt(Key, F, [Other|Bkt0]) ->
241
% {Bkt1,Dc} = on_key_bkt(Key, F, Bkt0),
244
%% update(Key, Fun, Dictionary) -> Dictionary.
201
%% %% first_key(Table) -> {ok,Key} | error.
202
%% %% Find the "first" key in a Table.
205
%% case next_bucket(T, 1) of
206
%% [?kv(K,Val)|Bkt] -> {ok,K};
207
%% [] -> error %No elements
210
%% next_bucket(T, Slot) when Slot > T#dict.n -> [];
211
%% next_bucket(T, Slot) ->
212
%% case get_bucket(T, Slot) of
213
%% [] -> next_bucket(T, Slot+1); %Empty bucket
217
%% %% next_key(Table, Key) -> {ok,NextKey} | error.
219
%% next_key(T, Key) ->
220
%% Slot = get_slot(T, Key),
221
%% B = get_bucket(T, Slot),
222
%% %% Find a bucket with something in it.
223
%% Bkt = case bucket_after_key(Key, B) of
224
%% no_key -> exit(badarg);
225
%% [] -> next_bucket(T, Slot+1);
229
%% [?kv(Next,Val)|_] -> {ok,Next};
230
%% [] -> error %We have reached the end!
233
%% bucket_after_key(Key, [?kv(Key,Val)|Bkt]) -> Bkt;
234
%% bucket_after_key(Key, [Other|Bkt]) ->
235
%% bucket_after_key(Key, Bkt);
236
%% bucket_after_key(Key, []) -> no_key. %Key not found!
238
%% %% on_key(Fun, Key, Dictionary) -> Dictionary.
240
%% on_key(F, Key, D0) ->
241
%% Slot = get_slot(D0, Key),
242
%% {D1,Dc} = on_bucket(fun (B0) -> on_key_bkt(Key, F, B0) end,
244
%% maybe_contract(D1, Dc).
246
%% on_key_bkt(Key, F, [?kv(Key,Val)|Bkt]) ->
248
%% {ok,New} -> {[?kv(Key,New)|Bkt],0};
251
%% on_key_bkt(Key, F, [Other|Bkt0]) ->
252
%% {Bkt1,Dc} = on_key_bkt(Key, F, Bkt0),
253
%% {[Other|Bkt1],Dc}.
255
-spec update(term(), fun((term()) -> term()), dict()) -> dict().
246
257
update(Key, F, D0) ->
247
258
Slot = get_slot(D0, Key),
248
{D1,_Uv} = on_bucket(fun (B0) -> update_bkt(Key, F, B0) end, D0, Slot),
259
try on_bucket(fun (B0) -> update_bkt(Key, F, B0) end, D0, Slot) of
262
badarg -> erlang:error(badarg, [Key, F, D0])
251
265
update_bkt(Key, F, [?kv(Key,Val)|Bkt]) ->
253
267
{[?kv(Key,Upd)|Bkt],Upd};
254
268
update_bkt(Key, F, [Other|Bkt0]) ->
255
269
{Bkt1,Upd} = update_bkt(Key, F, Bkt0),
271
update_bkt(_Key, _F, []) ->
258
%% update(Key, Fun, Init, Dictionary) -> Dictionary.
274
-spec update(term(), fun((term()) -> term()), term(), dict()) -> dict().
260
276
update(Key, F, Init, D0) ->
261
277
Slot = get_slot(D0, Key),
285
301
{[Other|Bkt1],Ic};
286
302
counter_bkt(Key, I, []) -> {[?kv(Key,I)],1}.
288
%% fold(FoldFun, Accumulator, Dictionary) -> Accumulator.
304
-spec fold(fun((term(), term(), term()) -> term()), term(), dict()) -> term().
289
305
%% Fold function Fun over all "bags" in Table and return Accumulator.
291
307
fold(F, Acc, D) -> fold_dict(F, Acc, D).
293
%% map(MapFun, Dictionary) -> Dictionary.
309
-spec map(fun((term(), term()) -> term()), dict()) -> dict().
295
311
map(F, D) -> map_dict(F, D).
297
%% filter(FilterFun, Dictionary) -> Dictionary.
313
-spec filter(fun((term(), term()) -> bool()), dict()) -> dict().
299
315
filter(F, D) -> filter_dict(F, D).
301
%% merge(MergeFun, Dictionary, Dictionary) -> Dictionary.
317
-spec merge(fun((term(), term(), term()) -> term()), dict(), dict()) -> dict().
303
319
merge(F, D1, D2) when D1#dict.size < D2#dict.size ->
304
320
fold_dict(fun (K, V1, D) ->