dict:filter()可以通過傳入乙個斷言作為引數,來對目標dict達到篩選的目的。
filter(f, d) -> filter_dict(f, d).
filter_dict(f, #dict = dict) when is_function(f, 2) ->
dict;
filter_dict(f, d) ->
segs0 = tuple_to_list(d#dict.segs),
= filter_seg_list(f, segs0, , 0),
maybe_contract(d#dict, fc).
filter_seg_list(f, [seg|segs], fss, fc0) ->
bkts0 = tuple_to_list(seg),
= filter_bkt_list(f, bkts0, , fc0),
filter_seg_list(f, segs, [list_to_tuple(bkts1)|fss], fc1);
filter_seg_list(f, , fss, fc) when is_function(f, 2) ->
.filter_bkt_list(f, [bkt0|bkts], fbs, fc0) ->
= filter_bucket(f, bkt0, , fc0),
filter_bkt_list(f, bkts, [bkt1|fbs], fc1);
filter_bkt_list(f, , fbs, fc) when is_function(f, 2) ->
.filter_bucket(f, [?kv(key,val)=e|bkt], fb, fc) ->
case f(key, val) of
true -> filter_bucket(f, bkt, [e|fb], fc);
false -> filter_bucket(f, bkt, fb, fc+1)
end;
filter_bucket(f, , fb, fc) when is_function(f, 2) ->
.
首先將dict的segs轉化為列表,依次從最前面的seg開始過濾。
在filter_seg_list()函式中,依次將seg化為列表,從列表的最開始依次在filter_bkt_list()中選擇slot,將slot資料依次在filter_bucket()中根據斷言的true or false放入結果列表的最前端,或者給表示未命中數的fc加一。
在完成了乙個slot的過濾後,翻轉列表以便正序。而後選在單個seg列表的下乙個slot進行過濾,同樣,乙個seg被過濾完後,同樣也會將結果進行逆序,確保結果的正序。
完成seg的過濾後選擇下乙個seg,過程與前者類似,但是最後結果再返回前,將結果單次seg的過濾結果轉化為元組。
在完成所有結果後,將結果轉化為元組作為原來的dict的segs。
但是由於過濾後dict資料的減少,需要將返回的dict進行縮容。通過maybe_contract()進行,同時傳入的還有代表剛才進行過濾而減少的元素個數fc。
maybe_contract(t, dc) when t#dict.size - dc < t#dict.con_size,
t#dict.n > ?seg_size ->
n = t#dict.n,
slot1 = n - t#dict.bso,
segs0 = t#dict.segs,
b1 = get_bucket_s(segs0, slot1),
slot2 = n,
b2 = get_bucket_s(segs0, slot2),
segs1 = put_bucket_s(segs0, slot1, b1 ++ b2),
segs2 = put_bucket_s(segs1, slot2, ), %clear the upper bucket
n1 = n - 1,
maybe_contract_segs(t#dict);
maybe_contract(t, dc) -> t#dict.
maybe_contract_segs(t) when t#dict.n =:= t#dict.bso ->
t#dict;
maybe_contract_segs(t) -> t.
如果原來dict的元素個數減去被過濾掉的個數仍舊大於需要縮容的大小con_size,那麼直接減去並返回,否則準備開始擴容。
縮容的邏輯與擴容類似,只是代表當前活躍個數的n來減去偏移量bso代表slot1,以便將最末尾的slot的資料放到slot1所定位到的slot上,並將原本最末尾的slot的資料清空,n-1表示活躍的slot減少乙個。
之後通過maybe_contract_segs()判斷是否要將當前的dict的segs容量減半。
在完成縮容後,返回的dict就是過濾後的dict。
erlang原始碼參考
1 資料型別的記憶體 2 siyao同學一系列介紹資料型別實現的文章 erlang資料型別的表示和實現 1 資料型別回顧 erlang資料型別的表示和實現 2 eterm 和立即數 erlang資料型別的表示和實現 3 列表 erlang資料型別的表示和實現 4 boxed 物件 erlang資料型...
Python原始碼剖析 Dict
為了刻畫某種關係,現代的程式語言都會提供關聯式的容器。關聯式容器中的元素分別是以 鍵 key 或值 value 這樣的形式存在。例如 3,5 3,6 就是一對對應的鍵與值。python中的關聯式容器是pydictobject。python通過pydictobject建立執行python位元組碼的執行...
redis原始碼剖析 dict
typedef struct dictentry v struct dictentry next dictentry typedef struct dicttype dicttype this is our hash table structure.every dictionary has two ...