erlang的dict原始碼解析 2

2021-08-21 12:58:20 字數 2426 閱讀 7764

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 ...