1995-08-09 08:06:35 -07:00
|
|
|
/***********************************************************************/
|
|
|
|
/* */
|
1996-04-30 07:53:58 -07:00
|
|
|
/* Objective Caml */
|
1995-08-09 08:06:35 -07:00
|
|
|
/* */
|
|
|
|
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
|
|
|
|
/* */
|
1996-04-30 07:53:58 -07:00
|
|
|
/* Copyright 1996 Institut National de Recherche en Informatique et */
|
1999-11-17 10:59:06 -08:00
|
|
|
/* en Automatique. All rights reserved. This file is distributed */
|
2001-12-07 05:41:02 -08:00
|
|
|
/* under the terms of the GNU Library General Public License, with */
|
|
|
|
/* the special exception on linking described in file ../LICENSE. */
|
1995-08-09 08:06:35 -07:00
|
|
|
/* */
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
/* The generic hashing primitive */
|
|
|
|
|
2003-12-15 10:10:51 -08:00
|
|
|
/* The interface of this file is in "mlvalues.h" */
|
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
#include "mlvalues.h"
|
2000-02-10 06:04:59 -08:00
|
|
|
#include "custom.h"
|
1995-05-04 03:15:53 -07:00
|
|
|
#include "memory.h"
|
|
|
|
|
2005-09-22 07:21:50 -07:00
|
|
|
static uintnat hash_accu;
|
|
|
|
static intnat hash_univ_limit, hash_univ_count;
|
1995-05-04 03:15:53 -07:00
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static void hash_aux(value obj);
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2004-01-02 11:23:29 -08:00
|
|
|
CAMLprim value caml_hash_univ_param(value count, value limit, value obj)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
hash_univ_limit = Long_val(limit);
|
|
|
|
hash_univ_count = Long_val(count);
|
|
|
|
hash_accu = 0;
|
|
|
|
hash_aux(obj);
|
|
|
|
return Val_long(hash_accu & 0x3FFFFFFF);
|
|
|
|
/* The & has two purposes: ensure that the return value is positive
|
|
|
|
and give the same result on 32 bit and 64 bit architectures. */
|
|
|
|
}
|
|
|
|
|
|
|
|
#define Alpha 65599
|
|
|
|
#define Beta 19
|
|
|
|
#define Combine(new) (hash_accu = hash_accu * Alpha + (new))
|
|
|
|
#define Combine_small(new) (hash_accu = hash_accu * Beta + (new))
|
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static void hash_aux(value obj)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
unsigned char * p;
|
1995-07-27 10:41:09 -07:00
|
|
|
mlsize_t i, j;
|
1995-05-04 03:15:53 -07:00
|
|
|
tag_t tag;
|
|
|
|
|
|
|
|
hash_univ_limit--;
|
|
|
|
if (hash_univ_count < 0 || hash_univ_limit < 0) return;
|
|
|
|
|
2002-01-20 09:39:10 -08:00
|
|
|
again:
|
1995-05-04 03:15:53 -07:00
|
|
|
if (Is_long(obj)) {
|
|
|
|
hash_univ_count--;
|
|
|
|
Combine(Long_val(obj));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1995-07-13 02:02:41 -07:00
|
|
|
/* Pointers into the heap are well-structured blocks. So are atoms.
|
1995-05-04 03:15:53 -07:00
|
|
|
We can inspect the block contents. */
|
2002-01-20 09:39:10 -08:00
|
|
|
|
|
|
|
Assert (Is_block (obj));
|
2007-11-06 07:16:56 -08:00
|
|
|
if (Is_young(obj) || Is_in_heap(obj) || Is_atom(obj)) {
|
1995-05-04 03:15:53 -07:00
|
|
|
tag = Tag_val(obj);
|
|
|
|
switch (tag) {
|
|
|
|
case String_tag:
|
|
|
|
hash_univ_count--;
|
2003-12-16 10:09:44 -08:00
|
|
|
i = caml_string_length(obj);
|
1995-05-04 03:15:53 -07:00
|
|
|
for (p = &Byte_u(obj, 0); i > 0; i--, p++)
|
|
|
|
Combine_small(*p);
|
|
|
|
break;
|
|
|
|
case Double_tag:
|
|
|
|
/* For doubles, we inspect their binary representation, LSB first.
|
|
|
|
The results are consistent among all platforms with IEEE floats. */
|
|
|
|
hash_univ_count--;
|
1996-07-01 05:43:28 -07:00
|
|
|
#ifdef ARCH_BIG_ENDIAN
|
1995-05-04 03:15:53 -07:00
|
|
|
for (p = &Byte_u(obj, sizeof(double) - 1), i = sizeof(double);
|
|
|
|
i > 0;
|
|
|
|
p--, i--)
|
|
|
|
#else
|
|
|
|
for (p = &Byte_u(obj, 0), i = sizeof(double);
|
|
|
|
i > 0;
|
|
|
|
p++, i--)
|
|
|
|
#endif
|
|
|
|
Combine_small(*p);
|
|
|
|
break;
|
1995-07-27 10:41:09 -07:00
|
|
|
case Double_array_tag:
|
|
|
|
hash_univ_count--;
|
|
|
|
for (j = 0; j < Bosize_val(obj); j += sizeof(double)) {
|
1996-07-01 05:43:28 -07:00
|
|
|
#ifdef ARCH_BIG_ENDIAN
|
1995-07-27 10:41:09 -07:00
|
|
|
for (p = &Byte_u(obj, j + sizeof(double) - 1), i = sizeof(double);
|
|
|
|
i > 0;
|
|
|
|
p--, i--)
|
|
|
|
#else
|
|
|
|
for (p = &Byte_u(obj, j), i = sizeof(double);
|
|
|
|
i > 0;
|
|
|
|
p++, i--)
|
|
|
|
#endif
|
|
|
|
Combine_small(*p);
|
|
|
|
}
|
|
|
|
break;
|
1995-05-04 03:15:53 -07:00
|
|
|
case Abstract_tag:
|
|
|
|
/* We don't know anything about the contents of the block.
|
|
|
|
Better do nothing. */
|
|
|
|
break;
|
1995-07-10 02:48:27 -07:00
|
|
|
case Infix_tag:
|
|
|
|
hash_aux(obj - Infix_offset_val(obj));
|
|
|
|
break;
|
2002-01-20 09:39:10 -08:00
|
|
|
case Forward_tag:
|
|
|
|
obj = Forward_val (obj);
|
|
|
|
goto again;
|
1997-05-11 15:42:38 -07:00
|
|
|
case Object_tag:
|
|
|
|
hash_univ_count--;
|
|
|
|
Combine(Oid_val(obj));
|
|
|
|
break;
|
2000-02-10 06:04:59 -08:00
|
|
|
case Custom_tag:
|
|
|
|
/* If no hashing function provided, do nothing */
|
|
|
|
if (Custom_ops_val(obj)->hash != NULL) {
|
|
|
|
hash_univ_count--;
|
|
|
|
Combine(Custom_ops_val(obj)->hash(obj));
|
|
|
|
}
|
|
|
|
break;
|
1995-05-04 03:15:53 -07:00
|
|
|
default:
|
|
|
|
hash_univ_count--;
|
|
|
|
Combine_small(tag);
|
|
|
|
i = Wosize_val(obj);
|
|
|
|
while (i != 0) {
|
|
|
|
i--;
|
|
|
|
hash_aux(Field(obj, i));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Otherwise, obj is a pointer outside the heap, to an object with
|
|
|
|
a priori unknown structure. Use its physical address as hash key. */
|
2005-09-22 07:21:50 -07:00
|
|
|
Combine((intnat) obj);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
2000-04-07 07:43:31 -07:00
|
|
|
|
|
|
|
/* Hashing variant tags */
|
|
|
|
|
2004-01-02 11:23:29 -08:00
|
|
|
CAMLexport value caml_hash_variant(char * tag)
|
2000-04-07 07:43:31 -07:00
|
|
|
{
|
|
|
|
value accu;
|
|
|
|
/* Same hashing algorithm as in ../typing/btype.ml, function hash_variant */
|
|
|
|
for (accu = Val_int(0); *tag != 0; tag++)
|
|
|
|
accu = Val_int(223 * Int_val(accu) + *((unsigned char *) tag));
|
2000-04-10 08:00:42 -07:00
|
|
|
#ifdef ARCH_SIXTYFOUR
|
2000-04-14 02:41:56 -07:00
|
|
|
accu = accu & Val_long(0x7FFFFFFFL);
|
2000-04-10 08:00:42 -07:00
|
|
|
#endif
|
2000-04-07 07:43:31 -07:00
|
|
|
/* Force sign extension of bit 31 for compatibility between 32 and 64-bit
|
|
|
|
platforms */
|
|
|
|
return (int32) accu;
|
|
|
|
}
|