Hash Bob Jenkins insensível ao caso?
-
22-07-2019 - |
Pergunta
Existe uma variante insensível ao caso da função de hash de Bob Jenkins?
Generics.Defaults.BobJenkinsHash
fornece uma função de hash rápida. Infelizmente, ele não pode ser usado em combinação com uma função de comparação insensível ao caso como So
TCustomStringComparer = class (TEqualityComparer <String>)
function Equals(const Left, Right: String): Boolean; override;
function GetHashCode(const Value: String): Integer; override;
end;
function TCustomStringComparer.Equals (const Left, Right : String) : Boolean;
begin
Result := CompareText (Left, Right) = 0;
end;
function TCustomStringComparer.GetHashCode (const Value : String) : Integer;
begin
Result := Generics.Defaults.BobJenkinsHash (Value [1], Length (Value) * SizeOf (Char), 0);
end;
Isso ocorre porque o tdictionary compara primeiro os códigos de hash e depois usa a comparação fornecida ao verificar a igualdade.
Claro que eu poderia usar maiúsculas no meu GetHashCode
Função, mas me perguntei se seria mais rápido se eu pudesse de alguma forma modificar a função de hash.
Solução
Não, não há uma versão invariante de casos da função de hash. Case inferior ou superior todas as cordas antes de passá -las para a função de hash.
Outras dicas
Seria um pouco mais rápido, mas prejudica muito sua manutenção. Raramente existe uma boa razão para esse tipo de micro-otimização. Basta converter suas cordas em caixa inferior ou superior antes de hash como você sugeriu.
"Devemos esquecer pequenas eficiências, digamos cerca de 97% das vezes: a otimização prematura é a raiz de todo o mal. No entanto, não devemos deixar passar nossas oportunidades nesse 3% crítico. Um bom programador não será preso à complacência por tal Raciocínio, ele será aconselhável olhar cuidadosamente para o código crítico; mas somente depois que esse código foi identificado " - Donald Knuth
IMO, toda a questão está errada. Para citar o Artigo da Wikipedia sobre funções de hash:
UMA função hash é qualquer procedimento bem definido ou função matemática que converte uma quantidade grande e possivelmente de tamanho variável de dados em um pequeno dado, geralmente um número inteiro único que pode servir como um índice para uma matriz.
Observe a "quantidade de dados" - não há tipo especificado e, de fato, a função de hash bob jenkins tem um parâmetro não topado const Data
apontando para os dados a serem hash. Como os dados de entrada não são necessariamente uma sequência de caracteres, não há como calcular um valor de hash "insensível ao caso". E mesmo se fosse uma sequência de caracteres - a parte superior ou inferior dependeria do conjunto de caracteres e da codificação. Então, você precisaria ter funções de hash diferentes para seqüências de caracteres ASCII, Strings codificadas UTF-8, Strings codificadas UTF-16 LE, ... (você entendeu a ideia).
Eu também precisava dessa função em um projeto. One-a-Time Hash de Bob Jenkin:
function hash(const s: string): cardinal;
var
p, last: PByte;
begin
if s = '' then exit(1);
p := pbyte(pointer(s));
last := p + length(s);
result := 0;
while p < last do begin
if {$ifdef asciionly}p^ < 128{$else}true{$endif} then begin
result := result + p^;
if (p^ >= ord('a')) and (p^ <= ord('z')) then result := result - ord('a') + ord('A');
result := result + (result shl 10);
result := result xor (result shr 6);
end;
inc(p);
end;
result := result + (result shl 3);
result := result xor (result shr 11);
result := result + (result shl 15);
end;
Se o Asciiony for definido, ele também deve dar o mesmo hash para as cordas UTF-8 e Latin1.
Não se esqueça de desativar a verificação de transbordamento.