目錄

名稱

Hash::Util - 一組通用的哈希子程序選擇

用法概覽

# Restricted hashes

use Hash::Util qw(
                   fieldhash fieldhashes

                   all_keys
                   lock_keys unlock_keys
                   lock_value unlock_value
                   lock_hash unlock_hash
                   lock_keys_plus
                   hash_locked hash_unlocked
                   hashref_locked hashref_unlocked
                   hidden_keys legal_keys

                   lock_ref_keys unlock_ref_keys
                   lock_ref_value unlock_ref_value
                   lock_hashref unlock_hashref
                   lock_ref_keys_plus
                   hidden_ref_keys legal_ref_keys

                   hash_seed hash_value hv_store
                   bucket_stats bucket_info bucket_array
                   lock_hash_recurse unlock_hash_recurse
                   lock_hashref_recurse unlock_hashref_recurse

                   hash_traversal_mask
                 );

my %hash = (foo => 42, bar => 23);
# Ways to restrict a hash
lock_keys(%hash);
lock_keys(%hash, @keyset);
lock_keys_plus(%hash, @additional_keys);

# Ways to inspect the properties of a restricted hash
my @legal = legal_keys(%hash);
my @hidden = hidden_keys(%hash);
my $ref = all_keys(%hash,@keys,@hidden);
my $is_locked = hash_locked(%hash);

# Remove restrictions on the hash
unlock_keys(%hash);

# Lock individual values in a hash
lock_value  (%hash, 'foo');
unlock_value(%hash, 'foo');

# Ways to change the restrictions on both keys and values
lock_hash  (%hash);
unlock_hash(%hash);

my $hashes_are_randomised = hash_seed() !~ /^\0+$/;

my $int_hash_value = hash_value( 'string' );

my $mask= hash_traversal_mask(%hash);

hash_traversal_mask(%hash,1234);

描述

Hash::UtilHash::Util::FieldHash 包含特殊函數,用於操作不真正需要關鍵字的哈希。

Hash::Util 包含一組支持受限哈希的函數。這些在本文檔中描述。 Hash::Util::FieldHash 包含一組支持在inside-out classes中使用哈希的函數,詳見Hash::Util::FieldHash

預設情況下,Hash::Util 不會導出任何內容。

受限哈希

5.8.0 引入了將哈希限制為特定鍵集合的能力。不能添加此集合之外的鍵。它還引入了鎖定單個鍵以防止刪除以及確保單個值無法更改的能力。

這主要用於取代已廢棄的偽哈希。

lock_keys
unlock_keys
lock_keys(%hash);
lock_keys(%hash, @keys);

將給定的 %hash 的鍵集合限制為 @keys。如果未給定 @keys,則將其限制為其當前鍵集合。不能再添加更多的鍵。delete() 和 exists() 仍將工作,但不會更改允許的鍵集合。 注意: 當哈希處於鎖定狀態時,當前實現會阻止該哈希被 bless()。任何嘗試這樣做的操作都將引

unlock_keys(%hash);

移除對 %hash 鍵集的限制。

請注意:如果哈希的任何值已被鎖定,則此子程序執行後它們將不會被解鎖。

這兩個例程都返回對操作的哈希的引用。

lock_keys_plus
lock_keys_plus(%hash,@additional_keys)

類似於 lock_keys(),不同之處在於可選鍵列表指定可能已存在或不存在於哈希中的鍵。基本上,這是一種更簡單的說法。

lock_keys(%hash,@additional_keys,keys %hash);

返回對 %hash 的引用

lock_value
unlock_value
lock_value  (%hash, $key);
unlock_value(%hash, $key);

鎖定和解鎖哈希的個別鍵的值。鎖定的鍵的值不能更改。

除非 %hash 已被鎖定,否則無論此設置如何,鍵/值都可以被刪除。

返回對 %hash 的引用。

lock_hash
unlock_hash
lock_hash(%hash);

lock_hash() 鎖定整個哈希,使所有鍵和值變為只讀。不能更改任何值,不能添加或刪除任何鍵。

unlock_hash(%hash);

unlock_hash() 與 lock_hash() 相反。所有鍵和值都變為可寫。所有值都可以更改,可以添加和刪除鍵。

返回對 %hash 的引用。

lock_hash_recurse
unlock_hash_recurse
lock_hash_recurse(%hash);

lock_hash() 鎖定整個哈希及其遞迴引用的任何哈希,使所有鍵和值變為只讀。不能更改任何值,不能添加或刪除任何鍵。

此方法對被另一個哈希引用的哈希進行遞迴。因此,哈希的哈希(HoH)將全部受限制,但哈希的哈希數組(HoAoH)將僅對頂部哈希進行限制。

unlock_hash_recurse(%hash);

unlock_hash_recurse() 與 lock_hash_recurse() 相反。所有鍵和值都變為可寫。所有值都可以更改,可以添加和刪除鍵。相同的遞迴限制適用於 lock_hash_recurse()。

返回對 %hash 的引用。

hashref_locked
hash_locked
hashref_locked(\%hash) and print "Hash is locked!\n";
hash_locked(%hash) and print "Hash is locked!\n";

如果哈希及其鍵已被鎖定,則返回 true。

hashref_unlocked
hash_unlocked
hashref_unlocked(\%hash) and print "Hash is unlocked!\n";
hash_unlocked(%hash) and print "Hash is unlocked!\n";

若雜湊及其鍵未鎖定,則返回 true。

my @keys = legal_keys(%hash);

返回受限制雜湊中合法鍵的列表。對於不受限制的雜湊,這等同於調用 keys(%hash)。

hidden_keys
my @keys = hidden_keys(%hash);

返回受限制雜湊中合法鍵的列表,但這些鍵未關聯任何值。因此,如果 'foo' 是 %hash 的“隱藏”鍵,則對於 definedexists 測試都將返回 false。

對於不受限制的雜湊,將返回空列表。

注意:這是一個實驗性功能,嚴重依賴於受限制雜湊的當前實現。如果實現更改,此例程可能變得無意義,此時將返回空列表。

all_keys
all_keys(%hash,@keys,@hidden);

將陣列 @keys 填充為所有通過 exists 測試的鍵,並將 @hidden 填充為未使用的其餘合法鍵。

返回雜湊的引用。

對於不受限制的雜湊,這將等同於

$ref = do {
    @keys = keys %hash;
    @hidden = ();
    \%hash
};

注意:這是一個實驗性功能,嚴重依賴於受限制雜湊的當前實現。如果實現更改,此例程可能變得無意義,此時將與對不受限制的雜湊的行為完全相同。

hash_seed
my $hash_seed = hash_seed();

hash_seed() 返回用於對雜湊排序進行隨機化的種子位元組。

請注意雜湊種子是敏感信息:通過知道它,可以對 Perl 代碼進行拒絕服務攻擊,甚至遠程進行,請參閱 perlsec 中的“Algorithmic Complexity Attacks”以獲取更多信息。不要將雜湊種子洩漏給不需要知道的人。另請參閱 perlrun 中的“PERL_HASH_SEED_DEBUG”。

在 Perl 5.17.6 之前,此函數返回 UV,現在返回一個字符串,其大小由 Perl 建構時使用的雜湊函數確定。可能的大小包括但不限於 4 個字節(對於大多數雜湊算法)和 16 個字節(對於 siphash)。

hash_value
my $hash_value = hash_value($string);
my $hash_value = hash_value($string, $seed);

hash_value($string) 返回給定字符串的當前 Perl 內部雜湊值。hash_value($string, $seed) 返回使用不同種子計算的雜湊值。如果自定義種子太短,則該函數將錯誤退出。種子的最小長度依賴於實現。

返回表示傳入字符串的雜湊值的 32 位整數。僅 1 個參數的值僅在進程的生存期內可靠。它可能因調用、環境變數、Perl 版本、架構和構建選項而異。

請注意給定字符串的雜湊值是敏感信息:通過知道它,可以推斷出雜湊種子,從而可以對 Perl 代碼進行拒絕服務攻擊,甚至遠程進行,請參閱 perlsec 中的“Algorithmic Complexity Attacks”以獲取更多信息。不要將字符串的雜湊值洩漏給不需要知道的人。另請參閱 perlrun 中的“PERL_HASH_SEED_DEBUG”。

bucket_info

回傳關於雜湊的基本資訊集。

my ($keys, $buckets, $used, @length_counts)= bucket_info($hash);

欄位如下

0: Number of keys in the hash
1: Number of buckets in the hash
2: Number of used buckets in the hash
rest : list of counts, Kth element is the number of buckets
       with K keys in it.

另見bucket_stats()和bucket_array()。

bucket_stats

回傳有關雜湊的統計資訊清單。

my ($keys, $buckets, $used, $quality, $utilization_ratio,
       $collision_pct, $mean, $stddev, @length_counts)
   = bucket_stats($hashref);

欄位如下

0: Number of keys in the hash
1: Number of buckets in the hash
2: Number of used buckets in the hash
3: Hash Quality Score
4: Percent of buckets used
5: Percent of keys which are in collision
6: Mean bucket length of occupied buckets
7: Standard Deviation of bucket lengths of occupied buckets
rest : list of counts, Kth element is the number of buckets
       with K keys in it.

另見bucket_info()和bucket_array()。

請注意,對於理想的雜湊,Hash Quality Score將為1,接近及低於1的數字表示良好的雜湊,顯著高於1的數字表示低分數。在實際應用中,它應該在0.95到1.05左右。它的定義如下

$score= sum( $count[$length] * ($length * ($length + 1) / 2) )
           /
           ( ( $keys / 2 * $buckets ) *
             ( $keys + ( 2 * $buckets ) - 1 ) )

此公式來自《紅龍書》(重構以使用可用的數據),並在http://www.strchr.com/hash_functions有文件記錄。

bucket_array
my $array= bucket_array(\%hash);

回傳與雜湊相關的桶子陣列的壓縮表示。陣列的每個元素都是一個整數K,若如此表示K個空桶,或者是指向另一個陣列的參考,該陣列包含在該桶中的鍵。

請注意,bucket_array返回的信息屬於敏感信息:通過知曉此信息,可以直接對perl的雜湊函數進行攻擊,進而可能對Perl代碼發起拒絕服務攻擊,甚至遠程攻擊,詳見perlsec中的“算法複雜度攻擊”以獲得更多信息。對於不需要知道此信息的人,請不要洩露此函數的輸出。另參見perlrun中的“PERL_HASH_SEED_DEBUG”。此函數僅供調試和診斷目的使用,很難想像在生產代碼中為什麼會使用它。

bucket_stats_formatted
print bucket_stats_formatted($hashref);

回傳由bucket_stats()返回的信息的格式化報告。示例報告如下

Keys: 50 Buckets: 33/64 Quality-Score: 1.01 (Good)
Utilized Buckets: 51.56% Optimal: 78.12% Keys In Collision: 34.00%
Chain Length - mean: 1.52 stddev: 0.66
Buckets 64          [0000000000000000000000000000000111111111111111111122222222222333]
Len   0 Pct:  48.44 [###############################]
Len   1 Pct:  29.69 [###################]
Len   2 Pct:  17.19 [###########]
Len   3 Pct:   4.69 [###]
Keys    50          [11111111111111111111111111111111122222222222222333]
Pos   1 Pct:  66.00 [#################################]
Pos   2 Pct:  28.00 [##############]
Pos   3 Pct:   6.00 [###]

第一組統計數據提供了一些摘要統計信息,包括將品質分數翻譯為“良好”、“差”和“劣質”,(分數≤1.05,分數≤1.2,分數>1.2)。有關詳細信息,請參見bucket_stats()中的文檔。

兩組條形圖提供了關於雜湊性能的統計數據和視覺指標。

第一組提供了關於桶鏈長度的數據,並提供了一個關於一次讀取*失敗*需要多少工作的洞察。在這種情況下,我們必須檢查桶中的每個項目,才能確定項目不在列表中。插入的性能與此情況相等,刪除在哈希中不存在的項目也是如此。

第二組提供了每個鏈中有多少個鍵的數據,並提供了一個關於一次讀取*命中*需要多少工作的概念。在哈希中更新或刪除項目的性能與此情況相等。

請注意,這些統計數據僅為摘要。實際性能將取決於存取哈希時的真實命中/未命中比率。如果您關心命中率,建議您通過使用類似以下的方式“過度大小化”您的哈希

keys(%hash)= keys(%hash) << $k;

慎選$k,可能是一個小數,如1或2。理論上,桶陣列越大,發生碰撞的機會越小。

hv_store
my $sv = 0;
hv_store(%hash,$key,$sv) or die "Failed to alias!";
$hash{$key} = 1;
print $sv; # prints 1

將變數的別名存儲在哈希中,而不是複製值。

hash_traversal_mask

從Perl 5.18開始,每個哈希都有自己的哈希遍歷順序,並且每次將新元素插入哈希時,此順序都會更改。這一功能是通過維護一個無符號整數遮罩(U32),在使用keys()、values()或each()遍歷哈希桶時,對實際桶ID進行xor運算實現的。

您可以使用此子程序來獲取和設置特定哈希的遍歷遮罩。設置遮罩可確保給定的哈希將產生相同的鍵順序。請注意,這並保證相同的哈希種子和遍歷遮罩將為兩個哈希產生相同的鍵順序,即使碰撞到一個桶中的項目也可能具有不同的順序。

bucket_ratio

此函數與Perl 5.25之前的scalar(%hash)行為相同。具體而言,如果哈希被綁定,則調用SCALAR綁定哈希方法,如果未綁定,則如果哈希為空,則返回0,否則返回一個包含哈希中使用的桶數量的字符串,後跟斜槓,後跟哈希中的總桶數量。

my %hash=("foo"=>1);
print Hash::Util::bucket_ratio(%hash); # prints "1/8"
used_buckets

此函數返回哈希中使用的桶的計數。計算此值的成本很高,並且不會緩存該值,因此請避免在生產代碼中使用此函數。

num_buckets

此函數返回哈希所持有的總桶數,或者如果數組被創建則將持有的桶數。(當哈希新創建時,即使此值非零,數組也可能尚未分配。)

對哈希引用進行操作。

本模組中大多數的子程序都有相等的版本,其操作對象是哈希的引用而不是原生哈希。以下是這些子程序的列表。它們除了名稱不同外,與原版相同,唯一的區別是它們接受一個 $hashref 作為參數,而不是 %hash,並且不帶原型。

lock_ref_keys
unlock_ref_keys
lock_ref_keys_plus
lock_ref_value
unlock_ref_value
lock_hashref
unlock_hashref
lock_hashref_recurse
unlock_hashref_recurse
hash_ref_unlocked
hidden_ref_keys

注意事項

請注意,限制操作的捕獲並非原子操作:例如

eval { %hash = (illegal_key => 1) }

會導致 %hash 變成空的,而不是保留其原始內容。

錯誤

此模組所暴露的接口非常接近於受限哈希的當前實現。預計隨著時間的推移,這種行為將得到擴展,並且介面將進一步抽象化。

作者

Michael G Schwern <schwern@pobox.com> 在 Nick Ing-Simmons 和 Jeffrey Friedl 的代碼基礎上製作。

hv_store() 來自於 Array::RefElem,版權 2000 Gisle Aas。

由 Yves Orton 提供的額外代碼。

hash_value($string, $seed) 的描述由 Christopher Yeleighton <ne01026@shark.2a.pl> 提供

參見

Scalar::UtilList::Utilperlsec 中的 "Algorithmic Complexity Attacks"

Hash::Util::FieldHash.