PageRenderTime 117ms CodeModel.GetById 43ms RepoModel.GetById 1ms app.codeStats 1ms

/src/hashtabl.d

https://github.com/ynd/clisp-branch--ynd-devel
D | 2963 lines | 2248 code | 93 blank | 622 comment | 348 complexity | c09f40476e14e66475816b187752819e MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0, BSD-3-Clause
  1. /*
  2. * Hash-Tables in CLISP
  3. * Bruno Haible 1990-2005
  4. * Sam Steingold 1998-2008
  5. * German comments translated into English: Stefan Kain 2002-01-29
  6. */
  7. #include "lispbibl.c"
  8. #include "arilev0.c" /* for Hashcode-Calculation */
  9. #include "aridecl.c" /* for Short-Floats */
  10. /* Structure of a Hash-Table:
  11. Pairs (Key . Value) are stored in a vector,
  12. which is indexed by (hashcode Key).
  13. For a running MAPHASH to be uninfluenced by a GC, this
  14. vector is not reorganized because of GC. But as every (hashcode key) can
  15. change on each GC, we build in an additional indexing-level:
  16. (hashcode Key) indexes an index-vector; an index points into the
  17. key-value-vector there, and the (key . value) is located there.
  18. In order to save memory, we do not store a cons (key . value)
  19. in the vector, but we simply store key and value consecutively.
  20. One might want to resolve collisions [several keys have the same
  21. (hascode Key)] with lists. Due to the fact that the key-value-vector
  22. (again because of MAPHASH) should be uninfluenced on GC and GC changes
  23. the set of collisions, we need an additional index-vector,
  24. called the next-vector, which is interlaced with the key-value-vector
  25. and which contains a "list"-structure.
  26. sketch:
  27. key --> (hashcode key) as index in index-vector.
  28. Key1 --> 3, Key2 --> 1, Key4 --> 3.
  29. index-vector #( nix {indexkey2} nix {indexkey1,indexkey4} nix ... )
  30. = #( nix 1 nix 0 nix ... )
  31. next-vector #( 3 nix leer nix leer)
  32. key-value-vector #( key1 val1 3 key2 val2 nix leer leer leer key4 val4 nix leer leer leer)
  33. access to a (Key . Value) - pair works as follows:
  34. index := (aref Index-Vektor (hashcode Key))
  35. until index = nix
  36. if (eql Key (aref KVVektor 3*index)) return (aref KVVektor 3*index+1)
  37. index := (aref Next-Vektor index) ; take "CDR" of the list
  38. = (aref KVVektor 3*index+2)
  39. return notfound.
  40. If the index-vector is enlarged, all hashcodes and the content of
  41. index-vector and the content of next-vector have to be recalculated.
  42. If the next-vector and key-value-vector are enlarged, the remaining
  43. elements can be filled with "leer" , without having to calculate
  44. a new hashcode.
  45. In order to have a fast MAPHASH following a CLRHASH or multiple REMHASH,
  46. when the table contains much fewer elements than its capacity,
  47. the entries could be kept "left-aligned" in the key-value-vector, i.e.
  48. all "leer" go to the right. Thus, MAPHASH only needs to graze over the
  49. elements count-1,...,1,0 of the key-value-vector. But REMHASH must
  50. - after it has created a gap - copy the last key-value-pair
  51. (Nummer count-1) into the gap.
  52. We treat such cases by possibly shrinking the key-value-vector and
  53. the next-vector on CLRHASH and REMHASH.
  54. We keep the "leer"-entries in next-vector in a free-"list", so that PUTHASH
  55. finds a free entry.
  56. The lengths of index-vector and next-vector do not depend on each other.
  57. We choose the ratio of their lengths to be 2:1.
  58. The hash-table is enlarged, when the free-list is empty, i.e.
  59. COUNT becomes greater than MAXCOUNT. Thereby, MAXCOUNT and SIZE are
  60. multiplied by REHASH-SIZE (>1).
  61. The hash-table is reduced, when COUNT < MINCOUNT. Thereby,
  62. MAXCOUNT and SIZE are multiplied with 1/REHASH-SIZE (<1) . We choose
  63. MINCOUNT = MAXCOUNT / REHASH-SIZE^2, so that COUNT can vary
  64. in both directions by the same amount (on a logarithmic scale)
  65. after the enlargement of the table.
  66. data-structure of the hash-table (see LISPBIBL.D):
  67. recflags codes the type and the state of the hash-table:
  68. Bit 0..3 encode the test and the hash-code function
  69. Bit 4..6 are state used to emit warnings for not GC-invariant keys
  70. Bit 7 set, when table must be reorganized after GC
  71. ht_size uintL>0 = length of the ITABLE
  72. ht_maxcount Fixnum>0 = length of the NTABLE
  73. ht_kvtable key-value-vector, a HashedAlist or WeakHashedAlist
  74. with 3*MAXCOUNT data fields and
  75. hal_itable index-vector of length SIZE
  76. hal_count number of entries in the table, <=MAXCOUNT
  77. hal_freelist start-index of the free-list
  78. ht_rehash_size growth-rate on reorganization. Float >1.1
  79. ht_mincount_threshold ratio MINCOUNT/MAXCOUNT = 1/rehash-size^2
  80. ht_mincount Fixnum>=0, lower bound for COUNT
  81. ht_test hash-table-test - for define-hash-table-test
  82. ht_hash hash function - for define-hash-table-test
  83. entry "leer" in key-value-vector is = #<UNBOUND>.
  84. entry "leer" in next-vector is filled by the free-list.
  85. entry "nix" in index-vector and in next-vector is = #<UNBOUND>. */
  86. #define leer unbound
  87. #define nix unbound
  88. #define HT_GOOD_P(ht) \
  89. (posfixnump(TheHashtable(ht)->ht_maxcount) && \
  90. posfixnump(TheHashtable(ht)->ht_mincount))
  91. /* ============================ Hash functions ============================ */
  92. /* Rotates a hashcode x by n bits to the left (0<n<32).
  93. rotate_left(n,x) */
  94. #define rotate_left(n,x) (((x) << (n)) | ((x) >> (32-(n))))
  95. /* mixes two hashcodes.
  96. one is rotated by 5 bits, then the other one is XOR-ed to it. */
  97. #define misch(x1,x2) (rotate_left(5,x1) ^ (x2))
  98. /* ------------------------------ FASTHASH EQ ------------------------------ */
  99. /* UP: Calculates the FASTHASH-EQ-hashcode of an object.
  100. hashcode1(obj)
  101. It is valid only until the next GC.
  102. (eq X Y) implies (= (hashcode1 X) (hashcode1 Y)).
  103. > obj: an object
  104. < result: hashcode, a 32-Bit-number */
  105. local uint32 hashcode1 (object obj);
  106. #if (defined(WIDE_HARD) || defined(WIDE_SOFT)) && defined(TYPECODES)
  107. #define hashcode1(obj) ((uint32)untype(obj))
  108. #else
  109. #define hashcode1(obj) ((uint32)as_oint(obj)) /* address (Bits 23..0) and typeinfo */
  110. #endif
  111. /* Tests whether hashcode1 of an object is guaranteed to be GC-invariant. */
  112. global bool gcinvariant_hashcode1_p (object obj) {
  113. return gcinvariant_object_p(obj);
  114. }
  115. /* ----------------------------- STABLEHASH EQ ----------------------------- */
  116. /* UP: Calculates the STABLEHASH-EQ-hashcode of an object.
  117. hashcode1stable(obj)
  118. It is valid across GC for instances of STANDARD-STABLEHASH, STRUCTURE-STABLEHASH.
  119. (eq X Y) implies (= (hashcode1 X) (hashcode1 Y)).
  120. > obj: an object
  121. < result: hashcode, a 32-Bit-number */
  122. global uint32 hashcode1stable (object obj) {
  123. if (instancep(obj)) {
  124. var object obj_forwarded = obj;
  125. instance_un_realloc(obj_forwarded);
  126. /* No need for instance_update here; if someone redefines a class in
  127. such a way that the hashcode slot goes away, the behaviour is
  128. undefined. */
  129. var object cv = TheInstance(obj_forwarded)->inst_class_version;
  130. var object clas = TheClassVersion(cv)->cv_class;
  131. if (!nullp(TheClass(clas)->subclass_of_stablehash_p)) {
  132. /* The hashcode slot is known to be at position 1, thanks to
  133. :FIXED-SLOT-LOCATIONS. */
  134. return posfixnum_to_V(TheInstance(obj_forwarded)->other[0]);
  135. }
  136. } else if (structurep(obj)) {
  137. if (!nullp(memq(S(structure_stablehash),TheStructure(obj)->structure_types))) {
  138. /* The hashcode slot is known to be at position 1, thanks to the way
  139. slots are inherited in DEFSTRUCT. */
  140. return posfixnum_to_V(TheStructure(obj)->recdata[1]);
  141. }
  142. } else if (symbolp(obj)) {
  143. var object hashcode = TheSymbol(obj)->hashcode;
  144. if (eq(hashcode,unbound)) {
  145. /* The first access to a symbol's hash code computes it. */
  146. pushSTACK(unbound); C_random_posfixnum(); hashcode = value1;
  147. TheSymbol(obj)->hashcode = hashcode;
  148. }
  149. return posfixnum_to_V(hashcode);
  150. }
  151. return hashcode1(obj);
  152. }
  153. /* UP: Tests whether an object is instance of STANDARD-STABLEHASH or
  154. STRUCTURE-STABLEHASH. */
  155. local inline bool instance_of_stablehash_p (object obj) {
  156. if (instancep(obj)) {
  157. var object obj_forwarded = obj;
  158. instance_un_realloc(obj_forwarded);
  159. var object cv = TheInstance(obj_forwarded)->inst_class_version;
  160. var object clas = TheClassVersion(cv)->cv_class;
  161. return !nullp(TheClass(clas)->subclass_of_stablehash_p);
  162. } else if (structurep(obj)) {
  163. return !nullp(memq(S(structure_stablehash),TheStructure(obj)->structure_types));
  164. }
  165. return false;
  166. }
  167. /* Tests whether hashcode1stable of an object is guaranteed to be
  168. GC-invariant. */
  169. global bool gcinvariant_hashcode1stable_p (object obj) {
  170. return gcinvariant_object_p(obj)
  171. || instance_of_stablehash_p(obj) || symbolp(obj);
  172. }
  173. /* ----------------------------- FASTHASH EQL ----------------------------- */
  174. /* UP: Calculates the FASTHASH-EQL-hashcode of an object.
  175. hashcode2(obj)
  176. It is valid only until the next GC.
  177. (eql X Y) implies (= (hashcode2 X) (hashcode2 Y)).
  178. > obj: an object
  179. < result: hashcode, a 32-Bit-number */
  180. global uint32 hashcode2 (object obj);
  181. /* auxiliary functions for known type:
  182. Fixnum: fixnum-value */
  183. local uint32 hashcode_fixnum (object obj);
  184. #if 0
  185. local uint32 hashcode_fixnum(object obj) { return hashcode1(obj); }
  186. #else
  187. #define hashcode_fixnum(obj) hashcode1(obj)
  188. #endif
  189. /* Bignum: length*2 + all digits */
  190. local uint32 hashcode_bignum (object obj) {
  191. var uintL len = (uintL)Bignum_length(obj); /* number of Words */
  192. var uint32 code = 2*len;
  193. var uintL pos;
  194. #if (intDsize==32)
  195. for (pos=0; pos<len; pos++)
  196. code = misch(code,TheBignum(obj)->data[pos]);
  197. #elif (intDsize==16)
  198. var uintL len1 = len & 1; /* len mod 2 */
  199. var uintL len2 = len - len1; /* len div 2 */
  200. for (pos=0; pos<len2; pos+=2)
  201. code = misch(code,highlow32(TheBignum(obj)->data[pos],
  202. TheBignum(obj)->data[pos+1]));
  203. if (len1 != 0) code = misch(code,TheBignum(obj)->data[len2]); /* LSD */
  204. #else /* (intDsize==8) */
  205. var uintL len1 = len & 3; /* len mod 4 */
  206. var uintL len2 = len - len1; /* len div 4 */
  207. for (pos=0; pos<len2; pos+=4)
  208. code = misch(code,( (((uint32)TheBignum(obj)->data[pos]) << 24)
  209. |(((uint32)TheBignum(obj)->data[pos+1]) << 16)
  210. |(((uint32)TheBignum(obj)->data[pos+2]) << 8)
  211. |(((uint32)TheBignum(obj)->data[pos+3]))));
  212. if (len1 != 0) {
  213. var uint32 lsd=0;
  214. for (pos=0; pos<len1; pos++)
  215. lsd |= ((uint32)TheBignum(obj)->data[len2+pos]) << (pos<<3);
  216. code = misch(code,lsd);
  217. }
  218. #endif
  219. return code;
  220. }
  221. /* Short-Float: internal representation */
  222. local uint32 hashcode_sfloat (object obj);
  223. #if 0
  224. local uint32 hashcode_sfloat(object obj) { return hashcode1(obj); }
  225. #else
  226. #define hashcode_sfloat(obj) hashcode1(obj)
  227. #endif
  228. /* Single-Float: 32 Bit */
  229. local uint32 hashcode_ffloat (object obj) {
  230. return ffloat_value(obj);
  231. }
  232. /* Double-Float: leading 32 Bits */
  233. local uint32 hashcode_dfloat (object obj) {
  234. #ifdef intQsize
  235. return (uint32)(TheDfloat(obj)->float_value >> 32);
  236. #else
  237. return TheDfloat(obj)->float_value.semhi;
  238. #endif
  239. }
  240. /* Long-Float: mixture of exponent, length, first 32 bits */
  241. extern uint32 hashcode_lfloat (object obj); /* see LFLOAT.D */
  242. /* in general: */
  243. global uint32 hashcode2 (object obj) {
  244. #ifdef TYPECODES
  245. if (!numberp(obj)) { /* a number? */
  246. /* no -> take EQ-hashcode (for characters, EQL == EQ) : */
  247. return hashcode1(obj);
  248. } else { /* yes -> differentiate according to typecode */
  249. switch (typecode(obj) & ~(bit(number_bit_t)|bit(sign_bit_t))) {
  250. case fixnum_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /* Fixnum */
  251. return hashcode_fixnum(obj);
  252. case bignum_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /* Bignum */
  253. return hashcode_bignum(obj);
  254. case sfloat_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /*Short-Float*/
  255. return hashcode_sfloat(obj);
  256. case ffloat_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /*Single-Float*/
  257. return hashcode_ffloat(obj);
  258. case dfloat_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /*Double-Float*/
  259. return hashcode_dfloat(obj);
  260. case lfloat_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /* Long-Float */
  261. return hashcode_lfloat(obj);
  262. case ratio_type & ~(bit(number_bit_t)|bit(sign_bit_t)): { /* Ratio */
  263. /* hash both components, mix */
  264. var uint32 code1 = hashcode2(TheRatio(obj)->rt_num);
  265. var uint32 code2 = hashcode2(TheRatio(obj)->rt_den);
  266. return misch(code1,code2);
  267. }
  268. case complex_type & ~(bit(number_bit_t)|bit(sign_bit_t)): { /* Complex */
  269. /* hash both components, mix */
  270. var uint32 code1 = hashcode2(TheComplex(obj)->c_real);
  271. var uint32 code2 = hashcode2(TheComplex(obj)->c_imag);
  272. return misch(code1,code2);
  273. }
  274. default: NOTREACHED;
  275. }
  276. }
  277. #else
  278. if (orecordp(obj))
  279. switch (Record_type(obj)) {
  280. case Rectype_Bignum:
  281. return hashcode_bignum(obj);
  282. case Rectype_Ffloat:
  283. return hashcode_ffloat(obj);
  284. case Rectype_Dfloat:
  285. return hashcode_dfloat(obj);
  286. case Rectype_Lfloat:
  287. return hashcode_lfloat(obj);
  288. case Rectype_Ratio: { /* hash both components, mix */
  289. var uint32 code1 = hashcode2(TheRatio(obj)->rt_num);
  290. var uint32 code2 = hashcode2(TheRatio(obj)->rt_den);
  291. return misch(code1,code2);
  292. }
  293. case Rectype_Complex: { /* hash both components, mix */
  294. var uint32 code1 = hashcode2(TheComplex(obj)->c_real);
  295. var uint32 code2 = hashcode2(TheComplex(obj)->c_imag);
  296. return misch(code1,code2);
  297. }
  298. default:
  299. break;
  300. }
  301. else if (immediate_number_p(obj)) {
  302. if (as_oint(obj) & wbit(4))
  303. return hashcode_sfloat(obj);
  304. else
  305. return hashcode_fixnum(obj);
  306. }
  307. return hashcode1(obj);
  308. #endif
  309. }
  310. /* Tests whether hashcode2 of an object is guaranteed to be GC-invariant. */
  311. global bool gcinvariant_hashcode2_p (object obj) {
  312. return numberp(obj) || gcinvariant_object_p(obj);
  313. }
  314. /* ---------------------------- STABLEHASH EQL ---------------------------- */
  315. /* UP: Calculates the STABLEHASH-EQL-hashcode of an object.
  316. hashcode2stable(obj)
  317. It is valid across GC for instances of STANDARD-STABLEHASH, STRUCTURE-STABLEHASH.
  318. (eql X Y) implies (= (hashcode2stable X) (hashcode2stable Y)).
  319. > obj: an object
  320. < result: hashcode, a 32-Bit-number */
  321. global uint32 hashcode2stable (object obj) {
  322. #ifdef TYPECODES
  323. if (!numberp(obj)) { /* a number? */
  324. /* no -> take EQ-hashcode (for characters, EQL == EQ) : */
  325. return hashcode1stable(obj);
  326. } else { /* yes -> differentiate according to typecode */
  327. switch (typecode(obj) & ~(bit(number_bit_t)|bit(sign_bit_t))) {
  328. case fixnum_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /* Fixnum */
  329. return hashcode_fixnum(obj);
  330. case bignum_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /* Bignum */
  331. return hashcode_bignum(obj);
  332. case sfloat_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /*Short-Float*/
  333. return hashcode_sfloat(obj);
  334. case ffloat_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /*Single-Float*/
  335. return hashcode_ffloat(obj);
  336. case dfloat_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /*Double-Float*/
  337. return hashcode_dfloat(obj);
  338. case lfloat_type & ~(bit(number_bit_t)|bit(sign_bit_t)): /* Long-Float */
  339. return hashcode_lfloat(obj);
  340. case ratio_type & ~(bit(number_bit_t)|bit(sign_bit_t)): { /* Ratio */
  341. /* hash both components, mix */
  342. var uint32 code1 = hashcode2(TheRatio(obj)->rt_num);
  343. var uint32 code2 = hashcode2(TheRatio(obj)->rt_den);
  344. return misch(code1,code2);
  345. }
  346. case complex_type & ~(bit(number_bit_t)|bit(sign_bit_t)): { /* Complex */
  347. /* hash both components, mix */
  348. var uint32 code1 = hashcode2(TheComplex(obj)->c_real);
  349. var uint32 code2 = hashcode2(TheComplex(obj)->c_imag);
  350. return misch(code1,code2);
  351. }
  352. default: NOTREACHED;
  353. }
  354. }
  355. #else
  356. if (orecordp(obj))
  357. switch (Record_type(obj)) {
  358. case Rectype_Bignum:
  359. return hashcode_bignum(obj);
  360. case Rectype_Ffloat:
  361. return hashcode_ffloat(obj);
  362. case Rectype_Dfloat:
  363. return hashcode_dfloat(obj);
  364. case Rectype_Lfloat:
  365. return hashcode_lfloat(obj);
  366. case Rectype_Ratio: { /* hash both components, mix */
  367. var uint32 code1 = hashcode2(TheRatio(obj)->rt_num);
  368. var uint32 code2 = hashcode2(TheRatio(obj)->rt_den);
  369. return misch(code1,code2);
  370. }
  371. case Rectype_Complex: { /* hash both components, mix */
  372. var uint32 code1 = hashcode2(TheComplex(obj)->c_real);
  373. var uint32 code2 = hashcode2(TheComplex(obj)->c_imag);
  374. return misch(code1,code2);
  375. }
  376. default:
  377. break;
  378. }
  379. else if (immediate_number_p(obj)) {
  380. if (as_oint(obj) & wbit(4))
  381. return hashcode_sfloat(obj);
  382. else
  383. return hashcode_fixnum(obj);
  384. }
  385. return hashcode1stable(obj);
  386. #endif
  387. }
  388. /* Tests whether hashcode2stable of an object is guaranteed to be
  389. GC-invariant. */
  390. global bool gcinvariant_hashcode2stable_p (object obj) {
  391. return numberp(obj)
  392. || gcinvariant_object_p(obj)
  393. || instance_of_stablehash_p(obj) || symbolp(obj);
  394. }
  395. /* ---------------------------- FASTHASH EQUAL ---------------------------- */
  396. /* UP: Calculates the FASTHASH-EQUAL-hashcode of an object.
  397. hashcode3(obj)
  398. It is valid only until the next GC, or the next modification
  399. of the object.
  400. (equal X Y) implies (= (hashcode3 X) (hashcode3 Y)).
  401. > obj: an object
  402. < result: hashcode, a 32-Bit-number */
  403. global uint32 hashcode3 (object obj);
  404. /* auxiliary functions for known type:
  405. String -> length + all characters */
  406. local uint32 hashcode_string (object obj) {
  407. var uintL len;
  408. var uintL offset;
  409. var object string = unpack_string_ro(obj,&len,&offset);
  410. var uint32 bish_code = 0x33DAE11FUL + len; /* utilize length */
  411. if (len > 0 && !simple_nilarray_p(string)) {
  412. SstringDispatch(string,X, {
  413. var const cintX* ptr = &((SstringX)TheVarobject(string))->data[offset];
  414. var uintC count = len;
  415. dotimespC(count,count, {
  416. var uint32 next_code = (uint32)(*ptr++); /* next character */
  417. bish_code = misch(bish_code,next_code); /* add */
  418. });
  419. });
  420. }
  421. return bish_code;
  422. }
  423. /* bit-vector -> length, first 16 bits, utilize last 16 bits */
  424. local uint32 hashcode_bvector (object obj) {
  425. var uintL len = vector_length(obj); /* length */
  426. var uintL index = 0;
  427. var object sbv = array_displace_check(obj,len,&index);
  428. /* sbv is the data-vector, index is the index into the data-vector. */
  429. len = len << sbNvector_atype(sbv);
  430. #if BIG_ENDIAN_P && (varobject_alignment%2 == 0)
  431. /* On big-endian-machines one can work with with 16 Bit at a time
  432. (so long as varobject_alignment is divisible by 2 byte): */
  433. #define bitpack 16
  434. #define uint_bitpack uint16
  435. #define get32bits_at highlow32_at
  436. #else
  437. /* else one can take only 8 bit at a time: */
  438. #define bitpack 8
  439. #define uint_bitpack uint8
  440. #define get32bits_at(p) \
  441. (((((((uint32)((p)[0])<<8)|(uint32)((p)[1]))<<8)|(uint32)((p)[2]))<<8)|(uint32)((p)[3]))
  442. #endif
  443. var uint_bitpack* ptr = /* pointer to the first used word */
  444. (uint_bitpack*)(&TheSbvector(sbv)->data[0]) + floor(index,bitpack);
  445. var uintL offset = index%bitpack; /* offset within the word */
  446. if (len <= 32) { /* length <= 32 -> take all bits: */
  447. if (len == 0) {
  448. return 0x8FA1D564UL;
  449. } else { /* 0<len<=32 */
  450. var uintL need = offset+len; /* need 'need' bits for now */
  451. /* need < 48 */
  452. var uint32 akku12 = 0; /* 48-Bit-Akku, part 1 and 2 */
  453. var uint32 akku3 = 0; /* 48-Bit-Akku, part 3 */
  454. #if (bitpack==16)
  455. if (need > 0) {
  456. akku12 = highlow32_0(*ptr++); /* first 16 bits */
  457. if (need > 16) {
  458. akku12 |= (uint32)(*ptr++); /* next 16 bits */
  459. if (need > 32)
  460. akku3 = (uint32)(*ptr++); /* last 16 bits */
  461. }
  462. }
  463. #endif
  464. #if (bitpack==8)
  465. if (need > 0) {
  466. akku12 = (uint32)(*ptr++)<<24; /* first 8 bits */
  467. if (need > 8) {
  468. akku12 |= (uint32)(*ptr++)<<16; /* next 8 bits */
  469. if (need > 16) {
  470. akku12 |= (uint32)(*ptr++)<<8; /* next 8 bits */
  471. if (need > 24) {
  472. akku12 |= (uint32)(*ptr++); /* next 8 bits */
  473. if (need > 32) {
  474. akku3 = (uint32)(*ptr++)<<8; /* next 8 bits */
  475. if (need > 40)
  476. akku3 |= (uint32)(*ptr++); /* last 8 bits */
  477. }
  478. }
  479. }
  480. }
  481. }
  482. #endif
  483. /* shift 'need' bits in akku12,akku3 by offset bits to the left: */
  484. akku12 = (akku12 << offset) | (uint32)high16(akku3 << offset);
  485. /* 32 bits in akku12 finished.
  486. mask out irrelevant bits: */
  487. akku12 = akku12 & ~(bit(32-len)-1);
  488. /* utilize length: */
  489. return akku12+len;
  490. }
  491. } else { /* length > 32 -> take first and last 16 bits: */
  492. var uint32 akku12 = /* 32-bit-akku */
  493. get32bits_at(ptr) << offset; /* contains at least the first 16 bits */
  494. offset += len; /* end-offset of the bitvector */
  495. ptr += floor(offset,bitpack); /* points to the last used word */
  496. offset = offset%bitpack; /* end-offset within the word */
  497. var uint32 akku34 = /* 32-bit-akku */
  498. get32bits_at(ptr-(16/bitpack)) << offset; /* contains at least the last 16 bits */
  499. /* reach for the first 16, last 16 bits and utilize length: */
  500. return highlow32(high16(akku12),high16(akku34)) + len;
  501. }
  502. #undef get32bits_at
  503. #undef uint_bitpack
  504. #undef bitpack
  505. }
  506. /* EQUALP-hashcode of a pathname-component. */
  507. #ifdef PATHNAME_WIN32
  508. global uint32 hashcode4 (object obj);
  509. #define hashcode_pathcomp(obj) hashcode4(obj)
  510. #else
  511. #define hashcode_pathcomp(obj) hashcode3(obj)
  512. #endif
  513. /* atom -> differentiation by type */
  514. local uint32 hashcode3_atom (object obj) {
  515. #ifdef TYPECODES
  516. if (symbolp(obj)) { /* a symbol? */
  517. return hashcode1(obj); /* yes -> take EQ-hashcode */
  518. } else if (numberp(obj)) { /* a number? */
  519. return hashcode2(obj); /* yes -> take EQL-hashcode */
  520. } else {
  521. var tint type = typecode(obj) /* typeinfo */
  522. & ~bit(notsimple_bit_t); /* if simple or not, is irrelevant */
  523. if (type >= (sbvector_type & ~bit(notsimple_bit_t)) /* bit/byte-vector ? */
  524. && type <= (sb32vector_type & ~bit(notsimple_bit_t)))
  525. return hashcode_bvector(obj); /* look at it component-wise */
  526. if (type == (sstring_type & ~bit(notsimple_bit_t))) /* string ? */
  527. return hashcode_string(obj); /* look at it component-wise */
  528. if (xpathnamep(obj)) { /* -> look at it component-wise: */
  529. check_SP();
  530. var uint32 bish_code = 0xB0DD939EUL;
  531. var const gcv_object_t* ptr = &((Record)ThePathname(obj))->recdata[0];
  532. var uintC count;
  533. dotimespC(count,Xrecord_length(obj), {
  534. var uint32 next_code = hashcode_pathcomp(*ptr++); /* hashcode of the next component */
  535. bish_code = misch(bish_code,next_code); /* add */
  536. });
  537. return bish_code;
  538. }
  539. /* else: take EQ-hashcode (for characters: EQL == EQ) */
  540. return hashcode1(obj);
  541. }
  542. #else
  543. if (orecordp(obj))
  544. switch (Record_type(obj)) {
  545. case_Rectype_number_above;
  546. case Rectype_Sbvector: case Rectype_bvector:
  547. case Rectype_Sb2vector: case Rectype_b2vector:
  548. case Rectype_Sb4vector: case Rectype_b4vector:
  549. case Rectype_Sb8vector: case Rectype_b8vector:
  550. case Rectype_Sb16vector: case Rectype_b16vector:
  551. case Rectype_Sb32vector: case Rectype_b32vector:
  552. return hashcode_bvector(obj);
  553. case Rectype_S8string: case Rectype_Imm_S8string:
  554. case Rectype_S16string: case Rectype_Imm_S16string:
  555. case Rectype_S32string: case Rectype_Imm_S32string:
  556. case Rectype_reallocstring: case Rectype_string:
  557. return hashcode_string(obj);
  558. #ifdef LOGICAL_PATHNAMES
  559. case Rectype_Logpathname:
  560. #endif
  561. case Rectype_Pathname: { /* pathname -> look at it component-wise: */
  562. check_SP();
  563. var uint32 bish_code = 0xB0DD939EUL;
  564. var gcv_object_t* ptr = &((Record)ThePathname(obj))->recdata[0];
  565. var uintC count;
  566. dotimespC(count,Xrecord_length(obj), {
  567. var uint32 next_code = hashcode_pathcomp(*ptr++); /* hashcode of the next component */
  568. bish_code = misch(bish_code,next_code); /* add */
  569. });
  570. return bish_code;
  571. }
  572. default:
  573. break;
  574. }
  575. else if (immediate_number_p(obj)) {
  576. case_number: return hashcode2(obj);
  577. }
  578. return hashcode1(obj);
  579. #endif
  580. }
  581. /* tree -> look at content up to depth 4, more if some paths end early
  582. determine the hashcode of the CAR and the hashcode of the CDR at a time
  583. and combine them shifted. As shifts we can choose, e.g. 16,7,5,3, because
  584. {0,16} + {0,7} + {0,5} + {0,3} = {0,3,5,7,8,10,12,15,16,19,21,23,24,26,28,31}
  585. consists of 16 different elements of {0,...,31} .
  586. > obj : the arbitrary object, tree(=cons) or leaf(=atom)
  587. > need : how many objects are still needed
  588. > level : the current distance from the root, to avoid circularity
  589. > hashcode_atom : how to compute the hash code of a leaf */
  590. #define HASHCODE_TREE_MAX_LEVEL 16
  591. #define HASHCODE_TREE_NEED_LEAVES 16
  592. local inline uint32 hashcode_tree_rec (object obj, int* need, int level,
  593. uint32 (hashcode_leaf) (object)) {
  594. if (atomp(obj)) {
  595. (*need)--;
  596. return hashcode_leaf(obj);
  597. } else if (level > HASHCODE_TREE_MAX_LEVEL || *need == 0) {
  598. return 1;
  599. } else {
  600. var local const uint8 shifts[4] = { 16 , 7 , 5 , 3 };
  601. var uint32 car_code = hashcode_tree_rec(Car(obj),need,level+1,hashcode_leaf);
  602. var uint32 cdr_code = *need == 0 ? 1 :
  603. hashcode_tree_rec(Cdr(obj),need,level+1,hashcode_leaf);
  604. return rotate_left(shifts[level & 3],car_code) ^ cdr_code;
  605. }
  606. }
  607. local inline uint32 hashcode_tree (object obj, uint32 (hashcode_leaf) (object))
  608. {
  609. int need = HASHCODE_TREE_NEED_LEAVES;
  610. return hashcode_tree_rec(obj,&need,0,hashcode_leaf);
  611. }
  612. /* similar to hashcode_tree
  613. NB: use the SAME top-level need initial value (e.g., HASHCODE_TREE_NEED_LEAVES)
  614. for the corresponding hashcode_tree and gcinvariant_hashcode_tree_p calls */
  615. local inline bool gcinvariant_hashcode_tree_p_rec
  616. (object obj, int* need, int level,
  617. bool (gcinvariant_hashcode_leaf_p) (object)) {
  618. if (atomp(obj)) {
  619. (*need)--;
  620. return gcinvariant_hashcode_leaf_p(obj);
  621. } else if (level > HASHCODE_TREE_MAX_LEVEL || *need == 0) {
  622. return true;
  623. } else {
  624. return gcinvariant_hashcode_tree_p_rec(Car(obj),need,level+1,
  625. gcinvariant_hashcode_leaf_p)
  626. && (*need == 0 ? true :
  627. gcinvariant_hashcode_tree_p_rec(Cdr(obj),need,level+1,
  628. gcinvariant_hashcode_leaf_p));
  629. }
  630. }
  631. local inline bool gcinvariant_hashcode_tree_p
  632. (object obj, bool (gcinvariant_hashcode_leaf_p) (object)) {
  633. int need = HASHCODE_TREE_NEED_LEAVES;
  634. return gcinvariant_hashcode_tree_p_rec(obj,&need,0,
  635. gcinvariant_hashcode_leaf_p);
  636. }
  637. #undef HASHCODE_TREE_MAX_LEVEL
  638. #undef HASHCODE_TREE_NEED_LEAVES
  639. global uint32 hashcode3 (object obj)
  640. { return hashcode_tree(obj,hashcode3_atom); }
  641. /* Tests whether hashcode3 of an object is guaranteed to be GC-invariant. */
  642. global bool gcinvariant_hashcode3_p (object obj);
  643. local bool gcinvariant_hashcode3_atom_p (object obj) {
  644. if (numberp(obj) || gcinvariant_object_p(obj))
  645. return true;
  646. #ifdef TYPECODES
  647. var tint type = typecode(obj) /* typeinfo */
  648. & ~bit(notsimple_bit_t); /* if simple or not, is irrelevant */
  649. if (type >= (sbvector_type & ~bit(notsimple_bit_t)) /* bit/byte-vector ? */
  650. && type <= (sb32vector_type & ~bit(notsimple_bit_t)))
  651. return true;
  652. if (type == (sstring_type & ~bit(notsimple_bit_t))) /* string ? */
  653. return true;
  654. /* Ignore the pathnames, for simplicity. */
  655. #else
  656. if (orecordp(obj))
  657. switch (Record_type(obj)) {
  658. case Rectype_Sbvector: case Rectype_bvector:
  659. case Rectype_Sb2vector: case Rectype_b2vector:
  660. case Rectype_Sb4vector: case Rectype_b4vector:
  661. case Rectype_Sb8vector: case Rectype_b8vector:
  662. case Rectype_Sb16vector: case Rectype_b16vector:
  663. case Rectype_Sb32vector: case Rectype_b32vector:
  664. case Rectype_S8string: case Rectype_Imm_S8string:
  665. case Rectype_S16string: case Rectype_Imm_S16string:
  666. case Rectype_S32string: case Rectype_Imm_S32string:
  667. case Rectype_reallocstring: case Rectype_string:
  668. return true;
  669. /* Ignore the pathnames, for simplicity. */
  670. default:
  671. break;
  672. }
  673. #endif
  674. return false;
  675. }
  676. global bool gcinvariant_hashcode3_p (object obj)
  677. { return gcinvariant_hashcode_tree_p(obj,gcinvariant_hashcode3_atom_p); }
  678. /* --------------------------- STABLEHASH EQUAL --------------------------- */
  679. /* UP: Calculates the STABLEHASH-EQUAL-hashcode of an object.
  680. hashcode3stable(obj)
  681. It is valid across GC if all cons-tree leaves are instances of
  682. STANDARD-STABLEHASH, STRUCTURE-STABLEHASH, but no longer than the next
  683. modification of the object.
  684. (equal X Y) implies (= (hashcode3stable X) (hashcode3stable Y)).
  685. > obj: an object
  686. < result: hashcode, a 32-Bit-number */
  687. global uint32 hashcode3stable (object obj);
  688. /* atom -> differentiation by type */
  689. local uint32 hashcode3stable_atom (object obj) {
  690. #ifdef TYPECODES
  691. if (symbolp(obj)) { /* a symbol? */
  692. return hashcode1stable(obj); /* yes -> take EQ-hashcode */
  693. } else if (numberp(obj)) { /* a number? */
  694. return hashcode2(obj); /* yes -> take EQL-hashcode */
  695. } else {
  696. var tint type = typecode(obj) /* typeinfo */
  697. & ~bit(notsimple_bit_t); /* if simple or not, is irrelevant */
  698. if (type >= (sbvector_type & ~bit(notsimple_bit_t)) /* bit/byte-vector ? */
  699. && type <= (sb32vector_type & ~bit(notsimple_bit_t)))
  700. return hashcode_bvector(obj); /* look at it component-wise */
  701. if (type == (sstring_type & ~bit(notsimple_bit_t))) /* string ? */
  702. return hashcode_string(obj); /* look at it component-wise */
  703. if (xpathnamep(obj)) { /* -> look at it component-wise: */
  704. check_SP();
  705. var uint32 bish_code = 0xB0DD939EUL;
  706. var const gcv_object_t* ptr = &((Record)ThePathname(obj))->recdata[0];
  707. var uintC count;
  708. dotimespC(count,Xrecord_length(obj), {
  709. var uint32 next_code = hashcode_pathcomp(*ptr++); /* hashcode of the next component */
  710. bish_code = misch(bish_code,next_code); /* add */
  711. });
  712. return bish_code;
  713. }
  714. /* else: take EQ-hashcode (for characters: EQL == EQ) */
  715. return hashcode1stable(obj);
  716. }
  717. #else
  718. if (orecordp(obj))
  719. switch (Record_type(obj)) {
  720. case_Rectype_number_above;
  721. case Rectype_Sbvector: case Rectype_bvector:
  722. case Rectype_Sb2vector: case Rectype_b2vector:
  723. case Rectype_Sb4vector: case Rectype_b4vector:
  724. case Rectype_Sb8vector: case Rectype_b8vector:
  725. case Rectype_Sb16vector: case Rectype_b16vector:
  726. case Rectype_Sb32vector: case Rectype_b32vector:
  727. return hashcode_bvector(obj);
  728. case Rectype_S8string: case Rectype_Imm_S8string:
  729. case Rectype_S16string: case Rectype_Imm_S16string:
  730. case Rectype_S32string: case Rectype_Imm_S32string:
  731. case Rectype_reallocstring: case Rectype_string:
  732. return hashcode_string(obj);
  733. #ifdef LOGICAL_PATHNAMES
  734. case Rectype_Logpathname:
  735. #endif
  736. case Rectype_Pathname: { /* pathname -> look at it component-wise: */
  737. check_SP();
  738. var uint32 bish_code = 0xB0DD939EUL;
  739. var gcv_object_t* ptr = &((Record)ThePathname(obj))->recdata[0];
  740. var uintC count;
  741. dotimespC(count,Xrecord_length(obj), {
  742. var uint32 next_code = hashcode_pathcomp(*ptr++); /* hashcode of the next component */
  743. bish_code = misch(bish_code,next_code); /* add */
  744. });
  745. return bish_code;
  746. }
  747. default:
  748. break;
  749. }
  750. else if (immediate_number_p(obj)) {
  751. case_number: return hashcode2(obj);
  752. }
  753. return hashcode1stable(obj);
  754. #endif
  755. }
  756. global uint32 hashcode3stable (object obj)
  757. { return hashcode_tree(obj,hashcode3stable_atom); }
  758. /* Tests whether hashcode3stable of an object is guaranteed to be
  759. GC-invariant. */
  760. global bool gcinvariant_hashcode3stable_p (object obj);
  761. local bool gcinvariant_hashcode3stable_atom_p (object obj) {
  762. if (numberp(obj) || gcinvariant_object_p(obj))
  763. return true;
  764. #ifdef TYPECODES
  765. var tint type = typecode(obj) /* typeinfo */
  766. & ~bit(notsimple_bit_t); /* if simple or not, is irrelevant */
  767. if (type >= (sbvector_type & ~bit(notsimple_bit_t)) /* bit/byte-vector ? */
  768. && type <= (sb32vector_type & ~bit(notsimple_bit_t)))
  769. return true;
  770. if (type == (sstring_type & ~bit(notsimple_bit_t))) /* string ? */
  771. return true;
  772. /* Ignore the pathnames, for simplicity. */
  773. #else
  774. if (orecordp(obj))
  775. switch (Record_type(obj)) {
  776. case Rectype_Sbvector: case Rectype_bvector:
  777. case Rectype_Sb2vector: case Rectype_b2vector:
  778. case Rectype_Sb4vector: case Rectype_b4vector:
  779. case Rectype_Sb8vector: case Rectype_b8vector:
  780. case Rectype_Sb16vector: case Rectype_b16vector:
  781. case Rectype_Sb32vector: case Rectype_b32vector:
  782. case Rectype_S8string: case Rectype_Imm_S8string:
  783. case Rectype_S16string: case Rectype_Imm_S16string:
  784. case Rectype_S32string: case Rectype_Imm_S32string:
  785. case Rectype_reallocstring: case Rectype_string:
  786. return true;
  787. /* Ignore the pathnames, for simplicity. */
  788. default:
  789. break;
  790. }
  791. #endif
  792. return instance_of_stablehash_p(obj) || symbolp(obj);
  793. }
  794. global bool gcinvariant_hashcode3stable_p (object obj)
  795. { return gcinvariant_hashcode_tree_p(obj,gcinvariant_hashcode3stable_atom_p); }
  796. /* ---------------------------- FASTHASH EQUALP ---------------------------- */
  797. /* UP: Calculates the EQUALP-hashcode of an object.
  798. hashcode4(obj)
  799. Is is valid only until the next GC or the next modification
  800. of the object.
  801. (equalp X Y) implies (= (hashcode4 X) (hashcode4 Y)). */
  802. global uint32 hashcode4 (object obj);
  803. /* auxiliary functions for known type:
  804. character -> case-insensitive. */
  805. #define hashcode4_char(c) (0xCAAEACEFUL + (uint32)as_cint(up_case(c)))
  806. /* number: mixture of exponent, length, first 32 bit */
  807. extern uint32 hashcode4_real (object obj); /* see REALELEM.D */
  808. extern uint32 hashcode4_uint32 (uint32 x); /* see REALELEM.D */
  809. extern uint32 hashcode4_uint4 [16]; /* see REALELEM.D */
  810. /* vectors: look at them component-wise */
  811. local uint32 hashcode4_vector_T (object dv, uintL index,
  812. uintL count, uint32 bish_code);
  813. local uint32 hashcode4_vector_Char (object dv, uintL index,
  814. uintL count, uint32 bish_code);
  815. local uint32 hashcode4_vector_Bit (object dv, uintL index,
  816. uintL count, uint32 bish_code);
  817. local uint32 hashcode4_vector_2Bit (object dv, uintL index,
  818. uintL count, uint32 bish_code);
  819. local uint32 hashcode4_vector_4Bit (object dv, uintL index,
  820. uintL count, uint32 bish_code);
  821. local uint32 hashcode4_vector_8Bit (object dv, uintL index,
  822. uintL count, uint32 bish_code);
  823. local uint32 hashcode4_vector_16Bit (object dv, uintL index,
  824. uintL count, uint32 bish_code);
  825. local uint32 hashcode4_vector_32Bit (object dv, uintL index,
  826. uintL count, uint32 bish_code);
  827. local uint32 hashcode4_vector (object dv, uintL index,
  828. uintL count, uint32 bish_code);
  829. local uint32 hashcode4_vector_T (object dv, uintL index,
  830. uintL count, uint32 bish_code) {
  831. if (count > 0) {
  832. check_SP();
  833. var const gcv_object_t* ptr = &TheSvector(dv)->data[index];
  834. dotimespL(count,count, {
  835. var uint32 next_code = hashcode4(*ptr++); /* next component's hashcode */
  836. bish_code = misch(bish_code,next_code); /* add */
  837. });
  838. }
  839. return bish_code;
  840. }
  841. local uint32 hashcode4_vector_Char (object dv, uintL index,
  842. uintL count, uint32 bish_code) {
  843. if (count > 0) {
  844. SstringDispatch(dv,X, {
  845. var const cintX* ptr = &((SstringX)TheVarobject(dv))->data[index];
  846. dotimespL(count,count, {
  847. var uint32 next_code = hashcode4_char(as_chart(*ptr++)); /*next char*/
  848. bish_code = misch(bish_code,next_code); /* add */
  849. });
  850. });
  851. }
  852. return bish_code;
  853. }
  854. local uint32 hashcode4_vector_Bit (object dv, uintL index,
  855. uintL count, uint32 bish_code) {
  856. if (count > 0) {
  857. var const uintB* ptr = &TheSbvector(dv)->data[index/8];
  858. dotimespL(count,count, {
  859. var uint32 next_code =
  860. hashcode4_uint4[(*ptr >> ((~index)%8)) & (bit(1)-1)]; /* next byte */
  861. bish_code = misch(bish_code,next_code); /* add */
  862. index++;
  863. ptr += ((index%8)==0);
  864. });
  865. }
  866. return bish_code;
  867. }
  868. local uint32 hashcode4_vector_2Bit (object dv, uintL index,
  869. uintL count, uint32 bish_code) {
  870. if (count > 0) {
  871. var const uintB* ptr = &TheSbvector(dv)->data[index/4];
  872. dotimespL(count,count, {
  873. var uint32 next_code =
  874. hashcode4_uint4[(*ptr >> ((~index)%4)) & (bit(2)-1)]; /* next byte */
  875. bish_code = misch(bish_code,next_code); /* add */
  876. index++;
  877. ptr += ((index%4)==0);
  878. });
  879. }
  880. return bish_code;
  881. }
  882. local uint32 hashcode4_vector_4Bit (object dv, uintL index,
  883. uintL count, uint32 bish_code) {
  884. if (count > 0) {
  885. var const uintB* ptr = &TheSbvector(dv)->data[index/2];
  886. dotimespL(count,count, {
  887. var uint32 next_code =
  888. hashcode4_uint4[(*ptr >> ((~index)%2)) & (bit(4)-1)]; /* next byte */
  889. bish_code = misch(bish_code,next_code); /* add */
  890. index++;
  891. ptr += ((index%2)==0);
  892. });
  893. }
  894. return bish_code;
  895. }
  896. local uint32 hashcode4_vector_8Bit (object dv, uintL index,
  897. uintL count, uint32 bish_code) {
  898. if (count > 0) {
  899. var const uintB* ptr = &TheSbvector(dv)->data[index];
  900. dotimespL(count,count, {
  901. var uint32 next_code = hashcode4_uint32(*ptr++); /* next byte */
  902. bish_code = misch(bish_code,next_code); /* add */
  903. });
  904. }
  905. return bish_code;
  906. }
  907. local uint32 hashcode4_vector_16Bit (object dv, uintL index,
  908. uintL count, uint32 bish_code) {
  909. if (count > 0) {
  910. var const uint16* ptr = &((uint16*)&TheSbvector(dv)->data[0])[index];
  911. dotimespL(count,count, {
  912. var uint32 next_code = hashcode4_uint32(*ptr++); /* next byte */
  913. bish_code = misch(bish_code,next_code); /* add */
  914. });
  915. }
  916. return bish_code;
  917. }
  918. local uint32 hashcode4_vector_32Bit (object dv, uintL index,
  919. uintL count, uint32 bish_code) {
  920. if (count > 0) {
  921. var const uint32* ptr = &((uint32*)&TheSbvector(dv)->data[0])[index];
  922. dotimespL(count,count, {
  923. var uint32 next_code = hashcode4_uint32(*ptr++); /* next byte */
  924. bish_code = misch(bish_code,next_code); /* add */
  925. });
  926. }
  927. return bish_code;
  928. }
  929. local uint32 hashcode4_vector (object dv, uintL index,
  930. uintL count, uint32 bish_code) {
  931. switch (Array_type(dv)) {
  932. case Array_type_svector: /* simple-vector */
  933. return hashcode4_vector_T(dv,index,count,bish_code);
  934. case Array_type_sbvector: /* simple-bit-vector */
  935. return hashcode4_vector_Bit(dv,index,count,bish_code);
  936. case Array_type_sb2vector:
  937. return hashcode4_vector_2Bit(dv,index,count,bish_code);
  938. case Array_type_sb4vector:
  939. return hashcode4_vector_4Bit(dv,index,count,bish_code);
  940. case Array_type_sb8vector:
  941. return hashcode4_vector_8Bit(dv,index,count,bish_code);
  942. case Array_type_sb16vector:
  943. return hashcode4_vector_16Bit(dv,index,count,bish_code);
  944. case Array_type_sb32vector:
  945. return hashcode4_vector_32Bit(dv,index,count,bish_code);
  946. case Array_type_snilvector: /* (VECTOR NIL) */
  947. if (count > 0)
  948. return 0x2116ECD0 + bish_code;
  949. /*FALLTHROUGH*/
  950. case Array_type_sstring: /* simple-string */
  951. return hashcode4_vector_Char(dv,index,count,bish_code);
  952. default: NOTREACHED;
  953. }
  954. }
  955. /* atom -> differentiation by type */
  956. local uint32 hashcode4_atom (object obj) {
  957. #ifdef TYPECODES
  958. if (symbolp(obj)) { /* a symbol? */
  959. return hashcode1(obj); /* yes -> take EQ-hashcode */
  960. } else if (numberp(obj)) { /* a number? */
  961. /* yes -> take EQUALP-hashcode */
  962. if (complexp(obj)) {
  963. var uint32 code1 = hashcode4_real(TheComplex(obj)->c_real);
  964. var uint32 code2 = hashcode4_real(TheComplex(obj)->c_imag);
  965. /* important for combining, because of "complex canonicalization":
  966. if imagpart=0.0, then hashcode = hashcode4_real(realpart). */
  967. return code1 ^ rotate_left(5,code2);
  968. } else {
  969. return hashcode4_real(obj);
  970. }
  971. } else
  972. switch (typecode(obj))
  973. #else
  974. if (orecordp(obj)) {
  975. if (Record_type(obj) < rectype_longlimit)
  976. goto case_orecord;
  977. else
  978. goto case_lrecord;
  979. } else if (immediate_number_p(obj)) {
  980. case_real: return hashcode4_real(obj);
  981. } else if (charp(obj))
  982. goto case_char;
  983. else
  984. return hashcode1(obj);
  985. switch (0)
  986. #endif
  987. {
  988. case_bvector: /* bit-vector */
  989. case_b2vector: /* 2bit-vector */
  990. case_b4vector: /* 4bit-vector */
  991. case_b8vector: /* 8bit-vector */
  992. case_b16vector: /* 16bit-vector */
  993. case_b32vector: /* 32bit-vector */
  994. case_string: /* string */
  995. case_vector: { /* (VECTOR T), (VECTOR NIL) */
  996. /* look at it component-wise: */
  997. var uintL len = vector_length(obj); /* length */
  998. var uintL index = 0;
  999. var object dv = array_displace_check(obj,len,&index);
  1000. /* dv is the data-vector, index is the index into the data-vector. */
  1001. var uint32 bish_code = 0x724BD24EUL + len; /* utilize length */
  1002. return hashcode4_vector(dv,index,len,bish_code);
  1003. }
  1004. case_mdarray: { /* array with rank /=1 */
  1005. /* rank and dimensions, then look at it component-wise: */
  1006. var uint32 bish_code = 0xF1C90A73UL;
  1007. {
  1008. var uintC rank = Iarray_rank(obj);
  1009. if (rank > 0) {
  1010. var uintL* dimptr = &TheIarray(obj)->dims[0];
  1011. if (Iarray_flags(obj) & bit(arrayflags_dispoffset_bit))
  1012. dimptr++;
  1013. dotimespC(rank,rank, {
  1014. var uint32 next_code = (uint32)(*dimptr++);
  1015. bish_code = misch(bish_code,next_code);
  1016. });
  1017. }
  1018. }
  1019. {
  1020. var uintL len = TheIarray(obj)->totalsize;
  1021. var uintL index = 0;
  1022. var object dv = iarray_displace_check(obj,len,&index);
  1023. return hashcode4_vector(dv,index,len,bish_code);
  1024. }
  1025. }
  1026. #ifdef TYPECODES
  1027. _case_structure
  1028. _case_stream
  1029. #endif
  1030. case_orecord:
  1031. switch (Record_type(obj)) {
  1032. case_Rectype_bvector_above;
  1033. case_Rectype_b2vector_above;
  1034. case_Rectype_b4vector_above;
  1035. case_Rectype_b8vector_above;
  1036. case_Rectype_b16vector_above;
  1037. case_Rectype_b32vector_above;
  1038. case_Rectype_string_above;
  1039. case_Rectype_vector_above;
  1040. case_Rectype_mdarray_above;
  1041. case_Rectype_Closure_above;
  1042. case_Rectype_Instance_above;
  1043. #ifndef TYPECODES
  1044. case_Rectype_Symbol_above;
  1045. case Rectype_Ratio:
  1046. case Rectype_Ffloat: case Rectype_Dfloat: case Rectype_Lfloat:
  1047. case Rectype_Bignum:
  1048. goto case_real;
  1049. case Rectype_Complex: {
  1050. var uint32 code1 = hashcode4_real(TheComplex(obj)->c_real);
  1051. var uint32 code2 = hashcode4_real(TheComplex(obj)->c_imag);
  1052. /* important for combining, because of "complex canonicalization":
  1053. if imagpart=0.0, then hashcode = hashcode4_real(realpart). */
  1054. return code1 ^ rotate_left(5,code2);
  1055. }
  1056. #endif
  1057. default: ;
  1058. }
  1059. /* FIXME: The case that obj is a hash-table should be handled specially. */
  1060. { /* look at flags, type, components: */
  1061. var uintC len = SXrecord_nonweak_length(obj);
  1062. var uint32 bish_code =
  1063. 0x03168B8D + (Record_flags(obj) << 24) + (Record_type(obj) << 16) + len;
  1064. if (len > 0) {
  1065. check_SP();
  1066. var const gcv_object_t* ptr = &TheRecord(obj)->recdata[0];
  1067. var uintC count;
  1068. dotimespC(count,len, {
  1069. var uint32 next_code = hashcode4(*ptr++); /* next component's hashcode */
  1070. bish_code = misch(bish_code,next_code); /* add */
  1071. });
  1072. }
  1073. if (Record_type(obj) >= rectype_limit) {
  1074. var uintC xlen = Xrecord_xlength(obj);
  1075. if (xlen > 0) {
  1076. var const uintB* ptr = (uintB*)&TheRecord(obj)->recdata[len];
  1077. dotimespC(xlen,xlen, {
  1078. var uint32 next_code = *ptr++; /* next byte */
  1079. bish_code = misch(bish_code,next_code); /* add */
  1080. });
  1081. }
  1082. }
  1083. return bish_code;
  1084. }
  1085. case_char: /* character */
  1086. return hashcode4_char(char_code(obj));
  1087. #ifdef TYPECODES
  1088. case_machine: /* machine */
  1089. case_subr: /* subr */
  1090. case_system: /* frame-pointer, small-read-label, system */
  1091. #else
  1092. case_symbol: /* symbol */
  1093. #endif
  1094. case_closure: /* closure */
  1095. case_instance: /* instance */
  1096. case_lrecord:
  1097. /* take EQ-hashcode */
  1098. return hashcode1(obj);
  1099. default: NOTREACHED;
  1100. }
  1101. }
  1102. global uint32 hashcode4 (object obj)
  1103. { return hashcode_tree(obj,hashcode4_atom); }
  1104. /* Tests whether hashcode4 of an object is guaranteed to be GC-invariant. */
  1105. global bool gcinvariant_hashcode4_p (object obj);
  1106. local bool gcinvariant_hashcode4_atom_p (object obj) {
  1107. if (numberp(obj) || gcinvariant_object_p(obj))
  1108. return true;
  1109. #ifdef TYPECODES
  1110. var tint type = typecode(obj) /* typeinfo */
  1111. & ~bit(notsimple_bit_t); /* if simple or not, is irrelevant */
  1112. if (type >= (sbvector_type & ~bit(notsimple_bit_t)) /* bit/byte-vector ? */
  1113. && type <= (sb32vector_type & ~bit(notsimple_bit_t)))
  1114. return true;
  1115. if (type == (sstring_type & ~bit(notsimple_bit_t))) /* string ? */
  1116. return true;
  1117. /* Ignore other types of arrays and records, for simplicity. */
  1118. #else
  1119. if (orecordp(obj))
  1120. switch (Record_type(obj)) {
  1121. case Rectype_Sbvector: case Rectype_bvector:
  1122. case Rectype_Sb2vector: case Rectype_b2vector:
  1123. case Rectype_Sb4vector: case Rectype_b4vector:
  1124. case Rectype_Sb8vector: case Rectype_b8vector:
  1125. case Rectype_Sb16vector: case Rectype_b16vector:
  1126. case Rectype_Sb32vector: case Rectype_b32vector:
  1127. case Rectype_S8string: case Rectype_Imm_S8string:
  1128. case Rectype_S16string: case Rectype_Imm_S16string:
  1129. case Rectype_S32string: case Rectype_Imm_S32string:
  1130. case Rectype_reallocstring: case Rectype_string:
  1131. return true;
  1132. /* Ignore other types of arrays and records, for simplicity. */
  1133. default:
  1134. break;
  1135. }
  1136. #endif
  1137. return false;
  1138. }
  1139. global bool gcinvariant_hashcode4_p (object obj)
  1140. { return gcinvariant_hashcode_tree_p(obj,gcinvariant_hashcode4_atom_p); }
  1141. /* ----------------------------- USER DEFINED ----------------------------- */
  1142. /* hashcode for user-defined ht_test */
  1143. local uint32 hashcode_raw_user (object fun, object obj) {
  1144. pushSTACK(obj); funcall(fun,1);
  1145. value1 = check_uint32(value1);
  1146. return I_to_UL(value1);
  1147. }
  1148. /* =========================== Hash table record =========================== */
  1149. /* Specification of the flags in a hash-table: */
  1150. #define htflags_test_builtin_B (bit(1)|bit(0)) /* for distinguishing builtin tests */
  1151. #define htflags_test_eq_B ( 0 | 0 ) /* test is EQ */
  1152. #define htflags_test_eql_B ( 0 |bit(0)) /* test is EQL */
  1153. #define htflags_test_equal_B (bit(1)| 0 ) /* test is EQUAL */
  1154. #define htflags_test_equalp_B (bit(1)|bit(0)) /* test is EQUALP */
  1155. #define htflags_test_user_B bit(2) /* set for user-defined test */
  1156. /* hash code of instances of STANDARD-STABLEHASH, STRUCTURE-STABLEHASH
  1157. is GC-invariant */
  1158. #define htflags_stablehash_B bit(3)
  1159. /* Must call warn_forced_gc_rehash at the next opportunity */
  1160. #define htflags_pending_warn_forced_gc_rehash bit(4)
  1161. /* Warn when a key is being added whose hash code is not GC-invariant.
  1162. - define htflags_warn_gc_rehash_B bit(5)
  1163. Set after a key has been added whose hash code is not GC-invariant.
  1164. - define htflags_gc_rehash_B bit(6)
  1165. Set when the list structure is invalid and the table needs a rehash.
  1166. - define htflags_invalid_B bit(7)
  1167. Specification of the two types of Pseudo-Functions:
  1168. Specification for LOOKUP - Pseudo-Function:
  1169. lookup(ht,obj,allowgc,&KVptr,&Iptr)
  1170. > ht: hash-table
  1171. > obj: object
  1172. > allowgc: whether GC is allowed during hash lookup
  1173. < if found: result=true,
  1174. KVptr[0], KVptr[1] : key, value in key-value-vector,
  1175. KVptr[2] : index of next entry,
  1176. *Iptr : previous index pointing to KVptr[0..2]
  1177. < if not found: result=false,
  1178. *Iptr : entry belonging to key in index-vector
  1179. or an arbitrary element of the "list" starting there
  1180. can trigger GC - if allowgc is true */
  1181. typedef maygc bool (* lookup_Pseudofun) (object ht, object obj, bool allowgc, gcv_object_t** KVptr_, gcv_object_t** Iptr_);
  1182. /* Specification for HASHCODE - Pseudo-Function:
  1183. hashcode(obj)
  1184. > obj: object
  1185. < result: its hash code */
  1186. typedef uint32 (* hashcode_Pseudofun) (object obj);
  1187. /* Specification for TEST - Pseudo-Function:
  1188. test(obj1,obj2)
  1189. > obj1: object
  1190. > obj2: object
  1191. < result: true if they are considered equal */
  1192. typedef bool (* test_Pseudofun) (object obj1, object obj2);
  1193. /* Specification for GCINVARIANT - Pseudo-Function:
  1194. gcinvariant(obj)
  1195. > obj: object
  1196. < result: true if its hash code is guaranteed to be GC-invariant */
  1197. typedef bool (* gcinvariant_Pseudofun) (object obj);
  1198. /* Extract Pseudo-Functions of a hash-table: */
  1199. #define lookupfn(ht) \
  1200. (*(lookup_Pseudofun)ThePseudofun(TheHashtable(ht)->ht_lookupfn))
  1201. #define hashcodefn(ht) \
  1202. (*(hashcode_Pseudofun)ThePseudofun(TheHashtable(ht)->ht_hashcodefn))
  1203. #define testfn(ht) \
  1204. (*(test_Pseudofun)ThePseudofun(TheHashtable(ht)->ht_testfn))
  1205. #define gcinvariantfn(ht) \
  1206. (*(gcinvariant_Pseudofun)ThePseudofun(TheHashtable(ht)->ht_gcinvariantfn))
  1207. /* UP: Calculates the hashcode of an object with reference to a hashtable.
  1208. hashcode(ht,obj)
  1209. > ht: hash-table
  1210. > obj: object
  1211. < result: index into the index-vector
  1212. can trigger GC - for user-defined ht_test */
  1213. local inline /*maygc*/ uintL hashcode_raw (object ht, object obj) {
  1214. var uintB flags = record_flags(TheHashtable(ht));
  1215. GCTRIGGER_IF(flags & htflags_test_user_B, GCTRIGGER2(ht,obj));
  1216. return (flags & (htflags_test_builtin_B | htflags_stablehash_B)
  1217. ? hashcodefn(ht)(obj) /* General built-in hash code */
  1218. : !(flags & htflags_test_user_B)
  1219. ? hashcode1(obj) /* FASTHASH-EQ hashcode */
  1220. : hashcode_raw_user(TheHashtable(ht)->ht_hash,obj));
  1221. }
  1222. local inline uintL hashcode_cook (uint32 code, uintL size) {
  1223. /* divide raw hashcode CODE by SIZE: */
  1224. var uint32 rest;
  1225. divu_3232_3232(code,size,(void),rest=);
  1226. return rest;
  1227. }
  1228. local uintL hashcode (object ht, object obj) {
  1229. var uintL size = TheHashtable(ht)->ht_size;
  1230. return hashcode_cook(hashcode_raw(ht,obj),size);
  1231. }
  1232. /* UP: Calculates the hashcode of an object with reference to a hashtable.
  1233. hashcode_builtin(ht,obj)
  1234. > ht: hash-table with built-in test
  1235. > obj: object
  1236. < result: index into the index-vector */
  1237. local inline uintL hashcode_builtin (object ht, object obj) {
  1238. var uintL size = TheHashtable(ht)->ht_size;
  1239. var uintB flags = record_flags(TheHashtable(ht));
  1240. var uint32 coderaw =
  1241. (flags & (htflags_test_builtin_B | htflags_stablehash_B)
  1242. ? hashcodefn(ht)(obj) /* General built-in hash code */
  1243. : hashcode1(obj)); /* FASTHASH-EQ hashcode */
  1244. return hashcode_cook(coderaw,size);
  1245. }
  1246. /* UP: Calculates the hashcode of an object with reference to a hashtable.
  1247. hashcode_user(ht,obj)
  1248. > ht: hash-table with user-defined test
  1249. > obj: object
  1250. < result: index into the index-vector
  1251. can trigger GC */
  1252. local maygc uintL hashcode_user (object ht, object obj) {
  1253. var uintL size = TheHashtable(ht)->ht_size;
  1254. var uint32 coderaw = hashcode_raw_user(TheHashtable(ht)->ht_hash,obj);
  1255. return hashcode_cook(coderaw,size);
  1256. }
  1257. /* UP: Reorganizes a hash-table, after the hashcodes of the keys
  1258. have been modified by a GC.
  1259. rehash(ht);
  1260. > ht: hash-table
  1261. can trigger GC - for user-defined ht_test */
  1262. local /*maygc*/ object rehash (object ht) {
  1263. GCTRIGGER_IF(record_flags(TheHashtable(ht)) & htflags_test_user_B,
  1264. GCTRIGGER1(ht));
  1265. /* fill index-vector with "nix" : */
  1266. var object kvtable = TheHashtable(ht)->ht_kvtable;
  1267. var object Ivektor = TheHashedAlist(kvtable)->hal_itable; /* index-vector */
  1268. {
  1269. var gcv_object_t* ptr = &TheSvector(Ivektor)->data[0];
  1270. var uintL count = TheHashtable(ht)->ht_size; /* SIZE, >0 */
  1271. dotimespL(count,count, { *ptr++ = nix; } );
  1272. }
  1273. /* build up "list"-structure element-wise: */
  1274. var object index = TheHashtable(ht)->ht_maxcount; /* MAXCOUNT */
  1275. var uintL maxcount = posfixnum_to_V(index);
  1276. var gcv_object_t* KVptr = &TheHashedAlist(kvtable)->hal_data[3*maxcount]; /* end of kvtable */
  1277. var object freelist = nix;
  1278. var object count = Fixnum_0;
  1279. var bool user_defined_p =
  1280. ht_test_code_user_p(ht_test_code(record_flags(TheHashtable(ht))));
  1281. while (!eq(index,Fixnum_0)) { /* index=0 -> loop finished */
  1282. /* traverse the key-value-vector and the next-vector.
  1283. index = MAXCOUNT,...,0 (Fixnum),
  1284. KVptr = &TheHashedAlist(kvtable)->hal_data[3*index],
  1285. freelist = freelist up to now,
  1286. count = pair-counter as fixnum. */
  1287. index = fixnum_inc(index,-1); /* decrement index */
  1288. KVptr -= 3;
  1289. var object key = KVptr[0]; /* next key */
  1290. if (!eq(key,leer)) { /* /= "leer" ? */
  1291. if (user_defined_p)
  1292. pushSTACK(ht); /* save */
  1293. var uintL hashindex = hashcode(ht,key); /* its hashcode */
  1294. if (user_defined_p) { /* restore - don't have to restore fixnums! */
  1295. /* this implementation favors built-in ht-tests at the expense
  1296. of the user-defined ones */
  1297. ht = popSTACK();
  1298. kvtable = TheHashtable(ht)->ht_kvtable;
  1299. Ivektor = TheHashedAlist(kvtable)->hal_itable;
  1300. KVptr = &TheHashedAlist(kvtable)->hal_data[3*posfixnum_to_V(index)];
  1301. }
  1302. /* "list", that starts at entry hashindex, in order to extend index:
  1303. copy entry from index-vector to the next-vector
  1304. end replace with index (a pointer to this location) : */
  1305. var gcv_object_t* Iptr = &TheSvector(Ivektor)->data[hashindex];
  1306. KVptr[2] = *Iptr; /* copy entry into the next-vector */
  1307. *Iptr = index; /* and replace pointer to it */
  1308. count = fixnum_inc(count,1); /* count */
  1309. } else { /* lengthen freelist in the next-vector: */
  1310. KVptr[2] = freelist; freelist = index;
  1311. }
  1312. }
  1313. TheHashedAlist(kvtable)->hal_freelist = freelist; /* save freelist */
  1314. TheHashedAlist(kvtable)->hal_count = count; /* save number of pairs for consistency */
  1315. set_ht_valid(TheHashtable(ht)); /* hashtable is now completely organized */
  1316. return ht;
  1317. }
  1318. /* Warn if a hash table is rehashed because of a GC, degrading performance.
  1319. can trigger GC */
  1320. local maygc void warn_forced_gc_rehash (object ht) {
  1321. pushSTACK(NIL); pushSTACK(ht);
  1322. STACK_1 = CLSTEXT("Performance/scalability warning: The hash table ~S needs "
  1323. "to be rehashed after a garbage collection, since it "
  1324. "contains key whose hash code is not GC-invariant.");
  1325. funcall(S(warn),2);
  1326. }
  1327. /* UP: Searches a key in a hash-table.
  1328. hash_lookup_builtin(ht,obj,allowgc,&KVptr,&Iptr)
  1329. > ht: hash-table
  1330. > obj: object
  1331. > allowgc: whether GC is allowed during hash lookup
  1332. < if found: result=true,
  1333. KVptr[0], KVptr[1] : key, value in key-value-vector,
  1334. KVptr[2] : index of next entry,
  1335. *Iptr : previous index pointing to KVptr[0..2]
  1336. < if not found: result=false,
  1337. *Iptr : entry belonging to key in index-vector
  1338. or an arbitrary element of the "list" starting there
  1339. can trigger GC - if allowgc is true */
  1340. global /*maygc*/ bool hash_lookup_builtin (object ht, object obj, bool allowgc,
  1341. gcv_object_t** KVptr_,
  1342. gcv_object_t** Iptr_) {
  1343. GCTRIGGER_IF(allowgc, GCTRIGGER2(ht,obj));
  1344. #ifdef GENERATIONAL_GC
  1345. if (!ht_validp(TheHashtable(ht))) { /* hash-table must be reorganized? */
  1346. /* Rehash it before the warning, otherwise we risk an endless recursion. */
  1347. ht = rehash(ht);
  1348. /* Warn if *WARN-ON-HASHTABLE-NEEDING-REHASH-AFTER-GC* is true: */
  1349. if (!nullpSv(warn_on_hashtable_needing_rehash_after_gc)) {
  1350. if (allowgc) {
  1351. record_flags_clr(TheHashtable(ht),htflags_pending_warn_forced_gc_rehash);
  1352. pushSTACK(ht); pushSTACK(obj);
  1353. warn_forced_gc_rehash(ht);
  1354. obj = popSTACK(); ht = popSTACK();
  1355. if (!ht_validp(TheHashtable(ht))) /* must be reorganized again? */
  1356. ht = rehash(ht);
  1357. } else {
  1358. /* We cannot warn now, because in this call we are not allowed to
  1359. trigger GC, therefore we delay the call until the next opportunity. */
  1360. record_flags_set(TheHashtable(ht),htflags_pending_warn_forced_gc_rehash);
  1361. }
  1362. }
  1363. }
  1364. #endif
  1365. if (allowgc
  1366. && (record_flags(TheHashtable(ht)) & htflags_pending_warn_forced_gc_rehash)) {
  1367. /* Now is an opportunity to get rid of the pending warn_forced_gc_rehash task. */
  1368. record_flags_clr(TheHashtable(ht),htflags_pending_warn_forced_gc_rehash);
  1369. pushSTACK(ht); pushSTACK(obj);
  1370. warn_forced_gc_rehash(ht);
  1371. obj = popSTACK(); ht = popSTACK();
  1372. if (!ht_validp(TheHashtable(ht))) /* must be reorganized again? */
  1373. ht = rehash(ht);
  1374. }
  1375. ASSERT(ht_validp(TheHashtable(ht)));
  1376. var uintB flags = record_flags(TheHashtable(ht));
  1377. var uintL hashindex = hashcode_builtin(ht,obj); /* calculate hashcode */
  1378. var object kvtable = TheHashtable(ht)->ht_kvtable;
  1379. var gcv_object_t* Nptr = /* pointer to the current entry */
  1380. &TheSvector(TheHashedAlist(kvtable)->hal_itable)->data[hashindex];
  1381. var gcv_object_t* kvt_data = TheHashedAlist(kvtable)->hal_data;
  1382. while (!eq(*Nptr,nix)) { /* track "list" : "list" finished -> not found */
  1383. var uintL index = posfixnum_to_V(*Nptr); /* next index */
  1384. var gcv_object_t* Iptr = Nptr;
  1385. var gcv_object_t* KVptr = /* pointer to entries in key-value-vector */
  1386. kvt_data + 3*index;
  1387. var object key = KVptr[0];
  1388. /* compare key with obj: */
  1389. if ((flags & htflags_test_builtin_B) == htflags_test_eq_B
  1390. ? eq(key,obj) /* compare with EQ */
  1391. : testfn(ht)(key,obj)) {
  1392. /* object obj found */
  1393. *KVptr_ = KVptr; *Iptr_ = Iptr; return true;
  1394. }
  1395. Nptr = &KVptr[2]; /* pointer to index of next entry */
  1396. }
  1397. /* not found */
  1398. *Iptr_ = Nptr; return false;
  1399. }
  1400. #ifndef GENERATIONAL_GC
  1401. /* can trigger GC - if allowgc is true */
  1402. global /*maygc*/ bool hash_lookup_builtin_with_rehash (object ht, object obj, bool allowgc,
  1403. gcv_object_t** KVptr_, gcv_object_t** Iptr_) {
  1404. GCTRIGGER_IF(allowgc, GCTRIGGER2(ht,obj));
  1405. if (!ht_validp(TheHashtable(ht))) { /* hash-table must be reorganized? */
  1406. /* Rehash it before the warning, otherwise we risk an endless recursion. */
  1407. ht = rehash(ht);
  1408. /* Warn if *WARN-ON-HASHTABLE-NEEDING-REHASH-AFTER-GC* is true: */
  1409. if (!nullpSv(warn_on_hashtable_needing_rehash_after_gc)) {
  1410. if (allowgc) {
  1411. record_flags_clr(TheHashtable(ht),htflags_pending_warn_forced_gc_rehash);
  1412. pushSTACK(ht); pushSTACK(obj);
  1413. warn_forced_gc_rehash(ht);
  1414. obj = popSTACK(); ht = popSTACK();
  1415. if (!ht_validp(TheHashtable(ht))) /* must be reorganized again? */
  1416. ht = rehash(ht);
  1417. } else {
  1418. /* We cannot warn now, because in this call we are not allowed to
  1419. trigger GC, therefore we delay the call until the next opportunity. */
  1420. record_flags_set(TheHashtable(ht),htflags_pending_warn_forced_gc_rehash);
  1421. }
  1422. }
  1423. }
  1424. return hash_lookup_builtin(ht,obj,allowgc,KVptr_,Iptr_);
  1425. }
  1426. #endif
  1427. /* UP: Searches a key in a hash-table with user-defined test.
  1428. hash_lookup_user(ht,obj,allowgc,&KVptr,&Iptr)
  1429. > ht: hash-table
  1430. > obj: object
  1431. > allowgc: whether GC is allowed during hash lookup
  1432. < if found: result=true,
  1433. KVptr[0], KVptr[1] : key, value in key-value-vector,
  1434. KVptr[2] : index of next entry,
  1435. *Iptr : previous index pointing to KVptr[0..2]
  1436. < if not found: result=false,
  1437. *Iptr : entry belonging to key in index-vector
  1438. or an arbitrary element of the "list" starting there
  1439. can trigger GC - if allowgc is true */
  1440. global maygc bool hash_lookup_user (object ht, object obj, bool allowgc,
  1441. gcv_object_t** KVptr_, gcv_object_t** Iptr_) {
  1442. ASSERT(allowgc);
  1443. pushSTACK(ht); pushSTACK(obj);
  1444. if (!ht_validp(TheHashtable(ht))) /* hash-table must be reorganized */
  1445. ht = rehash(ht);
  1446. obj = STACK_0; /* rehash could trigger GC */
  1447. var uintL hashindex = hashcode_user(ht,obj); /* calculate hashcode */
  1448. obj = popSTACK(); ht = popSTACK();
  1449. var object kvtable = TheHashtable(ht)->ht_kvtable;
  1450. var gcv_object_t* Nptr = /* pointer to the current entry */
  1451. &TheSvector(TheHashedAlist(kvtable)->hal_itable)->data[hashindex];
  1452. var gcv_object_t* kvt_data = TheHashedAlist(kvtable)->hal_data;
  1453. var uintL i_n; /* Iptr-Nptr FIXME: This is not GC-safe */
  1454. while (!eq(*Nptr,nix)) { /* track "list" : "list" finished -> not found */
  1455. var uintL index = posfixnum_to_V(*Nptr); /* next index */
  1456. var gcv_object_t* Iptr = Nptr;
  1457. var gcv_object_t* KVptr = /* pointer to entries in key-value-vector */
  1458. kvt_data + 3*index;
  1459. Nptr = &KVptr[2]; /* pointer to index of next entry */
  1460. /* compare key with obj: */
  1461. pushSTACK(ht); pushSTACK(obj);
  1462. i_n = Iptr - Nptr;
  1463. pushSTACK(KVptr[0]); pushSTACK(obj); funcall(TheHashtable(ht)->ht_test,2);
  1464. obj = popSTACK(); ht = popSTACK();
  1465. kvtable = TheHashtable(ht)->ht_kvtable;
  1466. kvt_data = TheHashedAlist(kvtable)->hal_data;
  1467. KVptr = kvt_data + 3*index; Nptr = &KVptr[2];
  1468. Iptr = Nptr + i_n;
  1469. if (!nullp(value1)) {
  1470. /* object obj found */
  1471. *KVptr_ = KVptr; *Iptr_ = Iptr; return true;
  1472. }
  1473. }
  1474. /* not found */
  1475. *Iptr_ = Nptr; return false;
  1476. }
  1477. /* UP: Searches a key in a hash-table.
  1478. hash_lookup(ht,obj,allowgc,&KVptr,&Iptr)
  1479. > ht: hash-table
  1480. > obj: object
  1481. > allowgc: whether GC is allowed during hash lookup
  1482. < if found: result=true,
  1483. KVptr[0], KVptr[1] : key, value in key-value-vector,
  1484. KVptr[2] : index of next entry,
  1485. *Iptr : previous index pointing to KVptr[0..2]
  1486. < if not found: result=false,
  1487. *Iptr : entry belonging to key in index-vector
  1488. or an arbitrary element of the "list" starting there
  1489. can trigger GC - if allowgc is true */
  1490. #define hash_lookup(ht,obj,allowgc,KVptr_,Iptr_) \
  1491. lookupfn(ht)(ht,obj,allowgc,KVptr_,Iptr_)
  1492. /* UP: Tests whether the hash code of a given key in a hash table is stable
  1493. i.e. gc-invariant, or not.
  1494. > ht: hash-table
  1495. > obj: object
  1496. < result: true if the key's hash code is gc-invariant */
  1497. local inline bool hashcode_gc_invariant_p (object ht, object obj) {
  1498. return gcinvariantfn(ht)(obj);
  1499. }
  1500. /* Warn if adding an key to a hash table degrades its performance.
  1501. can trigger GC */
  1502. local maygc void warn_key_forces_gc_rehash (object ht, object key) {
  1503. pushSTACK(NIL); pushSTACK(ht); pushSTACK(key);
  1504. STACK_2 = CLSTEXT("Performance/scalability warning: The hash table ~S must "
  1505. "be rehashed after each garbage collection, since its "
  1506. "key ~S has a hash code that is not GC-invariant.");
  1507. funcall(S(warn),3);
  1508. }
  1509. /* Macro: Insers a key-value-pair into a hash-table.
  1510. hash_store(key,value);
  1511. > object ht: hash-table
  1512. > object freelist: Start of the free-list in next-vector, /= nix
  1513. > key: key
  1514. > value: value
  1515. > gcv_object_t* Iptr: arbitrary element of the "list", that belongs to key
  1516. can trigger GC */
  1517. #define hash_store(key,value) \
  1518. do { \
  1519. var uintL index = posfixnum_to_V(freelist); /* free index */ \
  1520. var object kvtable = TheHashtable(ht)->ht_kvtable; \
  1521. /* address of the free entries in key-value-vector: */ \
  1522. var gcv_object_t* KVptr = &TheHashedAlist(kvtable)->hal_data[3*index]; \
  1523. set_break_sem_2(); /* protect from breaks */ \
  1524. /* increment COUNT: */ \
  1525. TheHashedAlist(kvtable)->hal_count = fixnum_inc(TheHashedAlist(kvtable)->hal_count,1); \
  1526. /* save key and value: */ \
  1527. *KVptr++ = key; *KVptr++ = value; \
  1528. /* shorten free-list: */ \
  1529. TheHashedAlist(kvtable)->hal_freelist = *KVptr; \
  1530. /* insert free list-element index into the "list" \
  1531. (put it after resize to the list-start, \
  1532. because Iptr points into the index-vector, \
  1533. else put it to the list-end, \
  1534. because hash_lookup was ended with *Iptr=nix): */ \
  1535. *KVptr = *Iptr; *Iptr = freelist; \
  1536. { /* Set the htflags_gc_rehash_B bit if necessary. */ \
  1537. var bool this_key_forces_gc_rehash = false; \
  1538. var uintB flags = record_flags(TheHashtable(ht)); \
  1539. if (!(flags & htflags_test_user_B) && !(flags & htflags_gc_rehash_B)) \
  1540. if (!hashcode_gc_invariant_p(ht,key)) { \
  1541. record_flags_set(TheHashtable(ht),htflags_gc_rehash_B); \
  1542. this_key_forces_gc_rehash = true; \
  1543. } \
  1544. clr_break_sem_2(); /* allow breaks again */ \
  1545. if (this_key_forces_gc_rehash) \
  1546. if (record_flags(TheHashtable(ht)) & htflags_warn_gc_rehash_B) \
  1547. warn_key_forces_gc_rehash(ht,key); \
  1548. } \
  1549. } while(0)
  1550. /* hash_table_weak_type(ht)
  1551. > ht: hash-table
  1552. < result: symbol NIL/:KEY/:VALUE/:KEY-AND-VALUE/:KEY-OR-VALUE */
  1553. global object hash_table_weak_type (object ht) {
  1554. var object kvt = TheHashtable(ht)->ht_kvtable;
  1555. if (simple_vector_p(kvt))
  1556. return NIL;
  1557. else switch (Record_type(kvt)) {
  1558. case Rectype_WeakHashedAlist_Key: { return S(Kkey); }
  1559. case Rectype_WeakHashedAlist_Value: { return S(Kvalue); }
  1560. case Rectype_WeakHashedAlist_Either: { return S(Kkey_and_value); }
  1561. case Rectype_WeakHashedAlist_Both: { return S(Kkey_or_value); }
  1562. default: NOTREACHED;
  1563. }
  1564. }
  1565. /* UP: Allocates the key-value-table for a new hash-table.
  1566. allocate_kvt(weak,maxcount)
  1567. > weak: NIL or :KEY or :VALUE or :KEY-AND-VALUE or :KEY-OR-VALUE
  1568. > maxcount: number of key/value pairs to make room for
  1569. < result: a key-value-table
  1570. can trigger GC */
  1571. local inline maygc object allocate_kvt (object weak, uintL maxcount) {
  1572. if (nullp(weak)) {
  1573. var object kvt = allocate_vector(4+3*maxcount);
  1574. TheHashedAlist(kvt)->hal_freelist = nix; /* dummy as free-list */
  1575. return kvt;
  1576. } else {
  1577. var sintB rectype;
  1578. if (eq(weak,S(Kkey))) /* :KEY */
  1579. rectype = Rectype_WeakHashedAlist_Key;
  1580. else if (eq(weak,S(Kvalue))) /* :VALUE */
  1581. rectype = Rectype_WeakHashedAlist_Value;
  1582. else if (eq(weak,S(Kkey_and_value))) /* :KEY-AND-VALUE */
  1583. rectype = Rectype_WeakHashedAlist_Either;
  1584. else if (eq(weak,S(Kkey_or_value))) /* :KEY-OR-VALUE */
  1585. rectype = Rectype_WeakHashedAlist_Both;
  1586. else
  1587. NOTREACHED;
  1588. var object kvt = allocate_lrecord(rectype,4+3*maxcount,lrecord_type);
  1589. TheWeakHashedAlist(kvt)->wp_cdr = unbound; /* a GC-invariant dummy */
  1590. TheWeakHashedAlist(kvt)->whal_itable = unbound;
  1591. TheWeakHashedAlist(kvt)->whal_count = Fixnum_0;
  1592. TheWeakHashedAlist(kvt)->whal_freelist = nix; /* dummy as free-list */
  1593. var uintL i;
  1594. for (i = 0; i < maxcount; i++) {
  1595. TheWeakHashedAlist(kvt)->whal_data[3*i+0] = unbound;
  1596. TheWeakHashedAlist(kvt)->whal_data[3*i+1] = unbound;
  1597. TheWeakHashedAlist(kvt)->whal_data[3*i+2] = leer;
  1598. }
  1599. activate_weak(kvt); /* add to O(all_weakpointers) */
  1600. return kvt;
  1601. }
  1602. }
  1603. /* UP: Provides the numbers and vectors for a new hash-table.
  1604. prepare_resize(maxcount,mincount_threshold,weak)
  1605. > maxcount: wished new size MAXCOUNT
  1606. > mincount_threshold: short-float MINCOUNT-THRESHOLD
  1607. > weak: NIL or :KEY or :VALUE or :KEY-AND-VALUE or :KEY-OR-VALUE
  1608. < result: maxcount
  1609. < stack-layout: MAXCOUNT, SIZE, MINCOUNT, index-vector, key-value-vector.
  1610. decreases STACK by 5
  1611. can trigger GC */
  1612. local maygc uintL prepare_resize (object maxcount, object mincount_threshold,
  1613. object weak) {
  1614. prepare_resize_restart:
  1615. /* check, if maxcount is not a too big fixnum >0 : */
  1616. if (!posfixnump(maxcount))
  1617. goto check_maxcount;
  1618. {
  1619. var uintV maxcountV = posfixnum_to_V(maxcount);
  1620. var uintV sizeV = 2*maxcountV+1;
  1621. /* SIZE odd in order to improve the hash-function! */
  1622. if (!(sizeV <= (uintV)(vbitm(oint_data_len)-1)))
  1623. /* sizeV should fit into a fixnum */
  1624. goto check_maxcount;
  1625. if (!(sizeV <= (uintL)(bitm(intLsize)-1)))
  1626. /* sizeV should fit into an uintL */
  1627. goto check_maxcount;
  1628. /* numbers on the stack: */
  1629. pushSTACK(maxcount); /* MAXCOUNT */
  1630. pushSTACK(fixnum(sizeV)); /* SIZE */
  1631. /* MINCOUNT := (floor (* maxcount mincount-threshold)) */
  1632. pushSTACK(maxcount); pushSTACK(mincount_threshold); funcall(L(star),2);
  1633. pushSTACK(value1); funcall(L(floor),1);
  1634. pushSTACK(value1);
  1635. /* stack-layout: MAXCOUNT, SIZE, MINCOUNT.
  1636. allocate new vectors: */
  1637. pushSTACK(allocate_vector(sizeV)); /* supply index-vector */
  1638. pushSTACK(allocate_kvt(weak,maxcountV)); /* supply key-value-vector */
  1639. /* finished. */
  1640. return maxcountV;
  1641. }
  1642. check_maxcount: /* maxcount no fixnum or too big */
  1643. pushSTACK(weak); pushSTACK(mincount_threshold); /* save */
  1644. pushSTACK(NIL); /* no PLACE */
  1645. pushSTACK(maxcount); /* TYPE-ERROR slot DATUM */
  1646. pushSTACK(O(type_hashtable_size)); /* TYPE-ERROR slot EXPECTED-TYPE */
  1647. pushSTACK(maxcount);
  1648. check_value(type_error,GETTEXT("Hash table size ~S too large"));
  1649. maxcount = value1;
  1650. mincount_threshold = popSTACK(); weak = popSTACK(); /* restore */
  1651. goto prepare_resize_restart;
  1652. }
  1653. /* UP: Enlarges or diminishes a hash-table
  1654. resize(ht,maxcount)
  1655. > ht: hash-table
  1656. > maxcount: wished new size MAXCOUNT
  1657. < result: hash-table, EQ to the old one
  1658. can trigger GC */
  1659. local maygc object resize (object ht, object maxcount) {
  1660. pushSTACK(ht);
  1661. var uintL maxcountL =
  1662. prepare_resize(maxcount,TheHashtable(ht)->ht_mincount_threshold,
  1663. hash_table_weak_type(ht));
  1664. /* no GC from now on! */
  1665. var object KVvektor = popSTACK(); /* new key-value-vector */
  1666. var object Ivektor = popSTACK(); /* index-vector */
  1667. var object mincount = popSTACK(); /* MINCOUNT */
  1668. var object size = popSTACK(); /* SIZE */
  1669. maxcount = popSTACK();
  1670. ht = popSTACK();
  1671. TheHashedAlist(KVvektor)->hal_itable = Ivektor; /* enter new index-vector */
  1672. /* Fill new key-value-vector:
  1673. Loop over the old key-value-vector and
  1674. copy all key-value-pairs with key /= "leer" :
  1675. For traversing the old key-value-vector: */
  1676. var uintL oldcount = posfixnum_to_V(TheHashtable(ht)->ht_maxcount);
  1677. var object oldKVvektor = TheHashtable(ht)->ht_kvtable;
  1678. var gcv_object_t* oldKVptr = &TheHashedAlist(oldKVvektor)->hal_data[0];
  1679. /* For traversing the new key-value-vector: */
  1680. var uintL count = maxcountL;
  1681. var gcv_object_t* KVptr = &TheHashedAlist(KVvektor)->hal_data[0];
  1682. /* For counting: */
  1683. var object counter = Fixnum_0;
  1684. dotimesL(oldcount,oldcount, {
  1685. var object nextkey = *oldKVptr++; /* next key */
  1686. var object nextvalue = *oldKVptr++; /* and value */
  1687. oldKVptr++;
  1688. if (!eq(nextkey,leer)) {
  1689. /* take over the entry into the new key-value-vector: */
  1690. if (count==0) { /* is the new vector already full? */
  1691. /* There is not enough room!! */
  1692. pushSTACK(ht); /* hash-table */
  1693. error(serious_condition,
  1694. GETTEXT("internal error occured while resizing ~S"));
  1695. }
  1696. count--;
  1697. *KVptr++ = nextkey; *KVptr++ = nextvalue; /* file in new vector */
  1698. *KVptr++ = nix;
  1699. counter = fixnum_inc(counter,1); /* and count */
  1700. }
  1701. });
  1702. /* Mark 'count' pairs of the new key-value-vector as "leer" : */
  1703. dotimesL(count,count, { *KVptr++ = leer; *KVptr++ = leer; *KVptr++ = leer; } );
  1704. TheHashedAlist(KVvektor)->hal_count = counter; /* enter COUNT (for consistency) */
  1705. /* modify hash-table: */
  1706. set_break_sem_2(); /* protect from breaks */
  1707. set_ht_invalid(TheHashtable(ht)); /* table must still be reorganized */
  1708. TheHashtable(ht)->ht_size = posfixnum_to_V(size); /* enter new SIZE */
  1709. TheHashtable(ht)->ht_maxcount = maxcount; /* enter new MAXCOUNT */
  1710. TheHashtable(ht)->ht_kvtable = KVvektor; /* enter new key-value-vector */
  1711. TheHashtable(ht)->ht_mincount = mincount; /* enter new MINCOUNT */
  1712. clr_break_sem_2(); /* allow breaks again */
  1713. return ht;
  1714. }
  1715. /* Macro: Enlarges a hash-table until freelist /= nix
  1716. hash_prepare_store(hash_pos,key_pos);
  1717. > int literal: hash-table position in STACK
  1718. > int literal: key position in STACK
  1719. < object ht: hash-table
  1720. < object freelist: start of the free-list in the next-vector, /= nix
  1721. < gcv_object_t* Iptr: arbitrary element of the "list", that belongs to the key
  1722. for EQ/EQL/EQUAL/EQUALP hashtables the hash code changes after GC,
  1723. so the raw hashcode cannot be cached.
  1724. for user-defined hashtables, raw hashcode caching is good
  1725. (especially for the user-defined tables, where hashcode can trigger GC!)
  1726. can trigger GC */
  1727. #define hash_prepare_store(hash_pos,key_pos) \
  1728. do { \
  1729. ht = STACK_(hash_pos); \
  1730. freelist = TheHashedAlist(TheHashtable(ht)->ht_kvtable)->hal_freelist; \
  1731. if (eq(freelist,nix)) { /* free-list = empty "list" ? */ \
  1732. var uintB flags = record_flags(TheHashtable(ht)); \
  1733. var bool cacheable = ht_test_code_user_p(ht_test_code(flags)); /* not EQ|EQL|EQUAL|EQUALP */ \
  1734. var uintL hc_raw = cacheable ? hashcode_raw(ht,STACK_(key_pos)) : 0; \
  1735. ht = STACK_(hash_pos); /* hashcode_raw maygc */ \
  1736. do { /* hash-table must still be enlarged: */ \
  1737. /* calculate new maxcount: */ \
  1738. pushSTACK(TheHashtable(ht)->ht_maxcount); \
  1739. pushSTACK(TheHashtable(ht)->ht_rehash_size); /* REHASH-SIZE (>1) */ \
  1740. funcall(L(star),2); /* (* maxcount rehash-size), is > maxcount */ \
  1741. pushSTACK(value1); \
  1742. funcall(L(ceiling),1); /* (ceiling ...), integer > maxcount */ \
  1743. ht = resize(STACK_(hash_pos),value1); /* enlarge table */ \
  1744. ht = rehash(ht); /* and reorganize */ \
  1745. /* newly calculate the address of the entry in the index-vector: */ \
  1746. { var uintL hashindex = \
  1747. (cacheable ? hashcode_cook(hc_raw,TheHashtable(ht)->ht_size) \
  1748. : hashcode(ht,STACK_(key_pos))); \
  1749. var object kvtable = TheHashtable(ht)->ht_kvtable; \
  1750. Iptr = &TheSvector(TheHashedAlist(kvtable)->hal_itable)->data[hashindex]; \
  1751. freelist = TheHashedAlist(kvtable)->hal_freelist; \
  1752. } \
  1753. } while (eq(freelist,nix)); \
  1754. } \
  1755. } while(0)
  1756. /* UP: Deletes the content of a hash-table.
  1757. clrhash(ht);
  1758. > ht: hash-table */
  1759. local void clrhash (object ht) {
  1760. set_break_sem_2(); /* protect from breaks */
  1761. var object kvtable = TheHashtable(ht)->ht_kvtable;
  1762. /* Delete pairs and build up freelist: */
  1763. {
  1764. var object index = TheHashtable(ht)->ht_maxcount; /* MAXCOUNT */
  1765. var uintL maxcount = posfixnum_to_V(index);
  1766. var object freelist = nix;
  1767. if (maxcount > 0) {
  1768. var gcv_object_t* KVptr = &TheHashedAlist(kvtable)->hal_data[3*maxcount]; /* end of kvtable */
  1769. do {
  1770. index = fixnum_inc(index,-1); /* decrement index */
  1771. *--KVptr = freelist; /* delete next-index */
  1772. *--KVptr = leer; *--KVptr = leer; /* delete key and value */
  1773. freelist = index;
  1774. } while (!eq(index,Fixnum_0));
  1775. }
  1776. TheHashedAlist(kvtable)->hal_freelist = freelist; /* save freelist */
  1777. }
  1778. TheHashedAlist(kvtable)->hal_count = Fixnum_0; /* COUNT := 0 */
  1779. /* Fill index-vector with "nix" : */
  1780. var object Ivektor = TheHashedAlist(kvtable)->hal_itable; /* index-vector */
  1781. {
  1782. var gcv_object_t* ptr = &TheSvector(Ivektor)->data[0];
  1783. var uintL count = TheHashtable(ht)->ht_size; /* SIZE, >0 */
  1784. dotimespL(count,count, { *ptr++ = nix; } );
  1785. }
  1786. record_flags_clr(TheHashtable(ht),htflags_gc_rehash_B); /* no dangerous keys now */
  1787. set_ht_valid(TheHashtable(ht)); /* hashtable is now completely organized */
  1788. clr_break_sem_2(); /* allow breaks again */
  1789. }
  1790. /* UP: fetches the value of *eq-hashfunction*. */
  1791. local object get_eq_hashfunction (void) {
  1792. var object value = Symbol_value(S(eq_hashfunction));
  1793. if (eq(value,S(fasthash_eq)) || eq(value,S(stablehash_eq)))
  1794. return value;
  1795. else {
  1796. Symbol_value(S(eq_hashfunction)) = S(fasthash_eq);
  1797. pushSTACK(value); /* TYPE-ERROR slot DATUM */
  1798. pushSTACK(O(type_eq_hashfunction)); /* TYPE-ERROR slot EXPECTED-TYPE */
  1799. pushSTACK(S(fasthash_eq));
  1800. pushSTACK(value);
  1801. pushSTACK(S(stablehash_eq)); pushSTACK(S(fasthash_eq));
  1802. pushSTACK(S(eq_hashfunction));
  1803. pushSTACK(TheSubr(subr_self)->name);
  1804. error(type_error,
  1805. GETTEXT("~S: The value of ~S should be ~S or ~S, not ~S.\n"
  1806. "It has been reset to ~S."));
  1807. }
  1808. }
  1809. /* UP: fetches the value of *eql-hashfunction*. */
  1810. local object get_eql_hashfunction (void) {
  1811. var object value = Symbol_value(S(eql_hashfunction));
  1812. if (eq(value,S(fasthash_eql)) || eq(value,S(stablehash_eql)))
  1813. return value;
  1814. else {
  1815. Symbol_value(S(eql_hashfunction)) = S(fasthash_eql);
  1816. pushSTACK(value); /* TYPE-ERROR slot DATUM */
  1817. pushSTACK(O(type_eql_hashfunction)); /* TYPE-ERROR slot EXPECTED-TYPE */
  1818. pushSTACK(S(fasthash_eql));
  1819. pushSTACK(value);
  1820. pushSTACK(S(stablehash_eql)); pushSTACK(S(fasthash_eql));
  1821. pushSTACK(S(eql_hashfunction));
  1822. pushSTACK(TheSubr(subr_self)->name);
  1823. error(type_error,
  1824. GETTEXT("~S: The value of ~S should be ~S or ~S, not ~S.\n"
  1825. "It has been reset to ~S."));
  1826. }
  1827. }
  1828. /* UP: fetches the value of *equal-hashfunction*. */
  1829. local object get_equal_hashfunction (void) {
  1830. var object value = Symbol_value(S(equal_hashfunction));
  1831. if (eq(value,S(fasthash_equal)) || eq(value,S(stablehash_equal)))
  1832. return value;
  1833. else {
  1834. Symbol_value(S(equal_hashfunction)) = S(fasthash_equal);
  1835. pushSTACK(value); /* TYPE-ERROR slot DATUM */
  1836. pushSTACK(O(type_equal_hashfunction)); /* TYPE-ERROR slot EXPECTED-TYPE */
  1837. pushSTACK(S(fasthash_equal));
  1838. pushSTACK(value);
  1839. pushSTACK(S(stablehash_equal)); pushSTACK(S(fasthash_equal));
  1840. pushSTACK(S(equal_hashfunction));
  1841. pushSTACK(TheSubr(subr_self)->name);
  1842. error(type_error,
  1843. GETTEXT("~S: The value of ~S should be ~S or ~S, not ~S.\n"
  1844. "It has been reset to ~S."));
  1845. }
  1846. }
  1847. /* check the :WEAK argument and return it
  1848. can trigger GC */
  1849. local maygc object check_weak (object weak) {
  1850. check_weak_restart:
  1851. if (missingp(weak)) return NIL;
  1852. if (eq(weak,S(Kkey)) || eq(weak,S(Kvalue))
  1853. || eq(weak,S(Kkey_and_value)) || eq(weak,S(Kkey_or_value)))
  1854. return weak;
  1855. /* invalid */
  1856. pushSTACK(NIL); /* no PLACE */
  1857. pushSTACK(weak); /* TYPE-ERROR slot DATUM */
  1858. pushSTACK(O(type_weak_ht)); /* TYPE-ERROR slot EXPECTED-TYPE */
  1859. pushSTACK(NIL); pushSTACK(S(Kkey)); pushSTACK(S(Kvalue));
  1860. pushSTACK(S(Kkey_and_value)); pushSTACK(S(Kkey_or_value));
  1861. pushSTACK(weak); pushSTACK(TheSubr(subr_self)->name);
  1862. check_value(type_error,GETTEXT("~S: argument ~S should be ~S, ~S, ~S, ~S or ~S."));
  1863. weak = value1;
  1864. goto check_weak_restart;
  1865. }
  1866. /* (MAKE-HASH-TABLE [:test] [:size] [:rehash-size] [:rehash-threshold]
  1867. [:key-type] [:value-type]
  1868. [:weak] [:warn-if-needs-rehash-after-gc] [:initial-contents]), CLTL p. 283 */
  1869. LISPFUN(make_hash_table,seclass_read,0,0,norest,key,9,
  1870. (kw(initial_contents),kw(key_type),kw(value_type),
  1871. kw(warn_if_needs_rehash_after_gc),kw(weak),
  1872. kw(test),kw(size),kw(rehash_size),kw(rehash_threshold)) )
  1873. { /* The rehash-threshold correlates in our implementation to the
  1874. ratio MAXCOUNT : SIZE = ca. 1 : 2.
  1875. We ignore the rehash-threshold-argument, as both too big values and
  1876. also too small values could be harmful: 0.99 causes on average
  1877. too long access-times; 0.00001 causes, that SIZE = MAXCOUNT/threshold
  1878. could become a bignum too fast.
  1879. The additional initial-contents-argument is an alist = list of
  1880. (key . value) - pairs, that are used to initialize the table.
  1881. STACK layout:
  1882. initial-contents, key-type, value-type,
  1883. warn-if-needs-rehash-after-gc, weak,
  1884. test, size, rehash-size, rehash-threshold. */
  1885. var uintB flags;
  1886. var object lookuppfn;
  1887. var object hashcodepfn;
  1888. var object testpfn;
  1889. var object gcinvariantpfn;
  1890. check_test_restart: { /* check test-argument: */
  1891. var object test = STACK_3;
  1892. if (!boundp(test) || eq(test,S(eql)) || eq(test,L(eql)))
  1893. test = get_eql_hashfunction();
  1894. if (eq(test,S(fasthash_eql))) {
  1895. flags = htflags_test_eql_B; /* FASTHASH-EQL */
  1896. hashcodepfn = P(hashcode2);
  1897. gcinvariantpfn = P(gcinvariant_hashcode2_p);
  1898. testpfn = P(eql);
  1899. lookuppfn = P(hash_lookup_builtin);
  1900. } else if (eq(test,S(stablehash_eql))) {
  1901. flags = htflags_test_eql_B | htflags_stablehash_B; /* STABLEHASH-EQL */
  1902. hashcodepfn = P(hashcode2stable);
  1903. gcinvariantpfn = P(gcinvariant_hashcode2stable_p);
  1904. testpfn = P(eql);
  1905. lookuppfn = P(hash_lookup_builtin);
  1906. } else {
  1907. if (eq(test,S(eq)) || eq(test,L(eq)))
  1908. test = get_eq_hashfunction();
  1909. if (eq(test,S(fasthash_eq))) {
  1910. flags = htflags_test_eq_B; /* FASTHASH-EQ */
  1911. hashcodepfn = unbound; /* specially handled in hashcode_builtin */
  1912. gcinvariantpfn = P(gcinvariant_hashcode1_p);
  1913. testpfn = unbound; /* specially handled in hash_lookup_builtin */
  1914. lookuppfn = P(hash_lookup_builtin);
  1915. } else if (eq(test,S(stablehash_eq))) {
  1916. flags = htflags_test_eq_B | htflags_stablehash_B; /* STABLEHASH-EQ */
  1917. hashcodepfn = P(hashcode1stable);
  1918. gcinvariantpfn = P(gcinvariant_hashcode1stable_p);
  1919. testpfn = unbound; /* specially handled in hash_lookup_builtin */
  1920. lookuppfn = P(hash_lookup_builtin);
  1921. } else {
  1922. if (eq(test,S(equal)) || eq(test,L(equal)))
  1923. test = get_equal_hashfunction();
  1924. if (eq(test,S(fasthash_equal))) {
  1925. flags = htflags_test_equal_B; /* FASTHASH-EQUAL */
  1926. hashcodepfn = P(hashcode3);
  1927. gcinvariantpfn = P(gcinvariant_hashcode3_p);
  1928. testpfn = P(equal);
  1929. lookuppfn = P(hash_lookup_builtin);
  1930. } else if (eq(test,S(stablehash_equal))) {
  1931. flags = htflags_test_equal_B | htflags_stablehash_B; /* STABLEHASH-EQUAL */
  1932. hashcodepfn = P(hashcode3stable);
  1933. gcinvariantpfn = P(gcinvariant_hashcode3stable_p);
  1934. testpfn = P(equal);
  1935. lookuppfn = P(hash_lookup_builtin);
  1936. } else if (eq(test,S(equalp)) || eq(test,L(equalp))) {
  1937. flags = htflags_test_equalp_B; /* EQUALP */
  1938. hashcodepfn = P(hashcode4);
  1939. gcinvariantpfn = P(gcinvariant_hashcode4_p);
  1940. testpfn = P(equalp);
  1941. lookuppfn = P(hash_lookup_builtin);
  1942. } else {
  1943. hashcodepfn = unbound;
  1944. gcinvariantpfn = unbound;
  1945. testpfn = unbound;
  1946. lookuppfn = P(hash_lookup_user);
  1947. if (symbolp(test)) {
  1948. var object ht_test = get(test,S(hash_table_test));
  1949. if (!consp(ht_test)) goto test_error;
  1950. STACK_3 = ht_test;
  1951. flags = htflags_test_user_B; /* user-defined ht_test */
  1952. } else if (consp(test)) {
  1953. flags = htflags_test_user_B; /* ad hoc (user-defined ht_test) */
  1954. } else {
  1955. test_error:
  1956. pushSTACK(NIL); /* no PLACE */
  1957. pushSTACK(test); /* TYPE-ERROR slot DATUM */
  1958. pushSTACK(O(type_hashtable_test)); /* TYPE-ERROR slot EXPECTED-TYPE */
  1959. pushSTACK(test); pushSTACK(S(Ktest));
  1960. pushSTACK(S(make_hash_table));
  1961. check_value(type_error,GETTEXT("~S: illegal ~S argument ~S"));
  1962. STACK_3 = value1;
  1963. goto check_test_restart;
  1964. }
  1965. }
  1966. }
  1967. }
  1968. } /* flags contains the flags for the test. */
  1969. check_size: { /* check size-argument: */
  1970. var object size = STACK_2;
  1971. if (!boundp(size)) {
  1972. STACK_2 = Fixnum_1; /* 1 as default */
  1973. } else {
  1974. if (!posfixnump(size)) {
  1975. pushSTACK(NIL); /* no PLACE */
  1976. pushSTACK(size); /* TYPE-ERROR slot DATUM */
  1977. pushSTACK(O(type_posfixnum)); /* TYPE-ERROR slot EXPECTED-TYPE */
  1978. pushSTACK(size); pushSTACK(S(Ksize));
  1979. pushSTACK(S(make_hash_table));
  1980. check_value(type_error,GETTEXT("~S: ~S argument should be a fixnum >=0, not ~S"));
  1981. STACK_2 = value1;
  1982. goto check_size;
  1983. }
  1984. /* size is a fixnum >=0 */
  1985. if (eq(size,Fixnum_0))
  1986. STACK_2 = Fixnum_1; /* turn 0 into 1 */
  1987. }
  1988. } /* size is now a fixnum >0. */
  1989. check_rehash_size: { /* (OR (INTEGER 1 *) (FLOAT (1.0) *)) */
  1990. if (!boundp(STACK_1)) { /* default-rehash-size = 1.5s0 */
  1991. STACK_1 = make_SF(0,SF_exp_mid+1,(bit(SF_mant_len)*3)/2);
  1992. } else {
  1993. if (!floatp(STACK_1)) { /* Float is OK */
  1994. if (!integerp(STACK_1) || R_minusp(STACK_1) || eq(STACK_1,Fixnum_0)) {
  1995. /* else it should be a positive integer */
  1996. bad_rehash_size:
  1997. pushSTACK(NIL); /* no PLACE */
  1998. pushSTACK(STACK_(1+1)); /* TYPE-ERROR slot DATUM */
  1999. pushSTACK(O(type_hashtable_rehash_size)); /* EXPECTED-TYPE */
  2000. pushSTACK(STACK_(1+3)); pushSTACK(S(Krehash_size));
  2001. pushSTACK(S(make_hash_table));
  2002. check_value(type_error,GETTEXT("~S: ~S argument should be an integer or a float > 1, not ~S"));
  2003. STACK_1 = value1;
  2004. goto check_rehash_size;
  2005. }
  2006. /* As it is senseless to enlarge a table always only by a fixed
  2007. number of elements (results in disastrous inefficiency), we set
  2008. rehash-size := min(1 + rehash-size/size , 2.0) . */
  2009. pushSTACK(STACK_1); /* rehash-size */
  2010. pushSTACK(STACK_(2+1)); /* size */
  2011. funcall(L(slash),2); /* (/ rehash-size size) */
  2012. pushSTACK(value1);
  2013. funcall(L(plus_one),1); /* (1+ ...) */
  2014. pushSTACK(value1);
  2015. pushSTACK(make_SF(0,SF_exp_mid+2,bit(SF_mant_len))); /* 2.0s0 */
  2016. funcall(L(min),2); /* (MIN ... 2.0s0) */
  2017. STACK_1 = value1; /* =: rehash-size */
  2018. }
  2019. { /* check (> rehash-size 1) : */
  2020. pushSTACK(STACK_1); /* rehash-size */
  2021. pushSTACK(Fixnum_1); /* 1 */
  2022. funcall(L(greater),2); /* (> rehash-size 1) */
  2023. }
  2024. if (nullp(value1)) goto bad_rehash_size;
  2025. /* convert rehash-size into a short-float: */
  2026. pushSTACK(STACK_1); /* rehash-size */
  2027. pushSTACK(SF_0); /* 0.0s0 */
  2028. funcall(L(float),2); /* (FLOAT rehash-size 0.0s0) = (COERCE rehash-size 'SHORT-FLOAT) */
  2029. /* enforce (>= rehash-size 1.125s0) : */
  2030. pushSTACK(value1);
  2031. pushSTACK(make_SF(0,SF_exp_mid+1,(bit(SF_mant_len)/8)*9)); /* 1.125s0 */
  2032. funcall(L(max),2); /* (max rehash-size 1.125s0) */
  2033. STACK_1 = value1; /* =: rehash-size */
  2034. }
  2035. } /* rehash-size is a short-float >= 1.125 . */
  2036. check_rehash_threshold: { /* check rehash-threshold: should be real in [0;1]*/
  2037. var object rehash_threshold = STACK_0;
  2038. if (boundp(rehash_threshold)) { /* not specified -> OK */
  2039. if_realp(rehash_threshold, ;, goto bad_rehash_threshold;);
  2040. if (false) {
  2041. bad_rehash_threshold:
  2042. pushSTACK(NIL); /* no PLACE */
  2043. pushSTACK(rehash_threshold); /* TYPE-ERROR slot DATUM */
  2044. pushSTACK(O(type_hashtable_rehash_threshold)); /* TYPE-ERROR slot EXPECTED-TYPE */
  2045. pushSTACK(STACK_1); pushSTACK(S(Krehash_threshold));
  2046. pushSTACK(S(make_hash_table));
  2047. check_value(type_error,GETTEXT("~S: ~S argument should be a real between 0 and 1, not ~S"));
  2048. STACK_0 = value1;
  2049. goto check_rehash_threshold;
  2050. }
  2051. pushSTACK(Fixnum_1);
  2052. pushSTACK(rehash_threshold);
  2053. pushSTACK(Fixnum_0);
  2054. funcall(L(gtequal),3); /* (>= 1 rehash-threshold 0) */
  2055. if (nullp(value1)) goto bad_rehash_threshold;
  2056. }
  2057. }
  2058. { /* If the initial-contents-argument is specified, we set
  2059. size := (max size (length initial-contents)) , so afterwards, when
  2060. the initial-contents are written, the table needs not be enlarged: */
  2061. var object initial_contents = STACK_8;
  2062. if (boundp(initial_contents)) { /* specified ? */
  2063. var uintL initial_length = llength(initial_contents); /* length of the alist */
  2064. if (initial_length > posfixnum_to_V(STACK_2)) /* > size ? */
  2065. STACK_2 = fixnum(initial_length); /* yes -> enlarge size */
  2066. }
  2067. } /* size is a fixnum >0, >= (length initial-contents) . */
  2068. { /* calculate MINCOUNT-THRESHOLD = 1/rehash-size^2 : */
  2069. var object rehash_size = STACK_1;
  2070. pushSTACK(rehash_size);
  2071. pushSTACK(rehash_size);
  2072. funcall(L(star),2); /* (* rehash-size rehash-size) */
  2073. pushSTACK(value1);
  2074. funcall(L(slash),1); /* (/ ...) */
  2075. STACK_0 = value1;
  2076. }
  2077. /* STACK layout:
  2078. initial-contents, key-type, value-type,
  2079. warn-if-needs-rehash-after-gc, weak,
  2080. test, size, rehash-size, mincount-threshold
  2081. provide vectors etc., with size as MAXCOUNT: [STACK_4 == weak] */
  2082. STACK_4 = check_weak(STACK_4);
  2083. prepare_resize(STACK_2,STACK_0,STACK_4);
  2084. var object ht = allocate_hash_table(); /* new hash-tabelle */
  2085. /* fill: */
  2086. var object kvtable = popSTACK(); /* key-value-vector */
  2087. TheHashtable(ht)->ht_kvtable = kvtable;
  2088. TheHashedAlist(kvtable)->hal_itable = popSTACK(); /* index-vector */
  2089. TheHashtable(ht)->ht_mincount = popSTACK(); /* MINCOUNT */
  2090. TheHashtable(ht)->ht_size = posfixnum_to_V(popSTACK()); /* SIZE */
  2091. TheHashtable(ht)->ht_maxcount = popSTACK(); /* MAXCOUNT */
  2092. /* STACK layout:
  2093. initial-contents, key-type, value-type,
  2094. warn-if-needs-rehash-after-gc, weak,
  2095. test, size, rehash-size, mincount-threshold. */
  2096. TheHashtable(ht)->ht_mincount_threshold = popSTACK(); /*MINCOUNT-THRESHOLD*/
  2097. TheHashtable(ht)->ht_rehash_size = popSTACK(); /* REHASH-SIZE */
  2098. TheHashtable(ht)->ht_lookupfn = lookuppfn;
  2099. TheHashtable(ht)->ht_hashcodefn = hashcodepfn;
  2100. TheHashtable(ht)->ht_testfn = testpfn;
  2101. TheHashtable(ht)->ht_gcinvariantfn = gcinvariantpfn;
  2102. /* STACK layout:
  2103. initial-contents, key-type, value-type,
  2104. warn-if-needs-rehash-after-gc, weak, test, -. */
  2105. if (ht_test_code_user_p(ht_test_code(flags))) { /* user-defined ht_test */
  2106. STACK_0 = ht;
  2107. var object test = coerce_function(Car(STACK_1)); pushSTACK(test);
  2108. var object hash = coerce_function(Cdr(STACK_2));
  2109. ht = STACK_1;
  2110. TheHashtable(ht)->ht_test = popSTACK();
  2111. TheHashtable(ht)->ht_hash = hash;
  2112. }
  2113. /* Use warn-if-needs-rehash-after-gc argument. */
  2114. if (!missingp(STACK_3))
  2115. flags |= htflags_warn_gc_rehash_B;
  2116. record_flags_replace(TheHashtable(ht), flags);
  2117. clrhash(ht); /* empty table, COUNT := 0 */
  2118. skipSTACK(6);
  2119. /* stack-layout: initial-contents. */
  2120. {
  2121. pushSTACK(ht);
  2122. while (consp(STACK_1)) { /* if it was specified, so long as it was a cons: */
  2123. var object next = Car(STACK_1); /* alist element */
  2124. if (consp(next)) { /* a cons (Key . Value) ? */
  2125. /* execute (SYSTEM::PUTHASH (car next) hashtable (cdr next)) ,
  2126. whereby the table cannot grow: */
  2127. var gcv_object_t* KVptr;
  2128. var gcv_object_t* Iptr;
  2129. if (hash_lookup(STACK_0,Car(next),true,&KVptr,&Iptr)) { /* search */
  2130. /* already found -> was already contained in the alist further
  2131. on the left, and in alists the first association (left)
  2132. shadows all other associations of the same key. */
  2133. ht = STACK_0; /* restore ht */
  2134. } else { /* not found -> make a new entry: */
  2135. var object freelist = /* start of the free-list in the next-vector */
  2136. TheHashedAlist(TheHashtable(STACK_0)->ht_kvtable)->hal_freelist;
  2137. if (eq(freelist,nix)) { /* empty "list" ? */
  2138. pushSTACK(STACK_0); /* hash-table */
  2139. pushSTACK(S(make_hash_table));
  2140. error(serious_condition,
  2141. GETTEXT("~S: internal error while building ~S"));
  2142. }
  2143. ht = STACK_0; /* restore ht */
  2144. next = Car(STACK_1); /* restore next */
  2145. hash_store(Car(next),Cdr(next)); /* make entry */
  2146. }
  2147. }
  2148. STACK_1 = Cdr(STACK_1); /* pop alist */
  2149. }
  2150. skipSTACK(2); /* drop ht, initial-contents */
  2151. }
  2152. VALUES1(ht); /* hash-table as value */
  2153. }
  2154. /* UP: Searches an object in a hash-table.
  2155. gethash(obj,ht,allowgc)
  2156. > obj: object, as key
  2157. > ht: hash-table
  2158. > allowgc: whether GC is allowed during hash lookup
  2159. (should be true if the hash-table has a user-defined test)
  2160. < result: if found, belonging value, else nullobj
  2161. can trigger GC - if allowgc is true */
  2162. global /*maygc*/ object gethash (object obj, object ht, bool allowgc) {
  2163. GCTRIGGER_IF(allowgc, GCTRIGGER2(obj,ht));
  2164. var gcv_object_t* KVptr;
  2165. var gcv_object_t* Iptr;
  2166. if (hash_lookup(ht,obj,allowgc,&KVptr,&Iptr))
  2167. return KVptr[1]; /* found -> value */
  2168. else
  2169. return nullobj;
  2170. }
  2171. /* error, if an argument is not a hash-table
  2172. check_hashtable(obj);
  2173. > obj: object
  2174. < hashtable
  2175. can trigger GC */
  2176. local maygc object check_hashtable (object obj) {
  2177. while (!hash_table_p(obj)) {
  2178. pushSTACK(NIL); /* no PLACE */
  2179. pushSTACK(obj); /* TYPE-ERROR slot DATUM */
  2180. pushSTACK(S(hash_table)); /* TYPE-ERROR slot EXPECTED-TYPE */
  2181. pushSTACK(obj);
  2182. pushSTACK(TheSubr(subr_self)->name);
  2183. check_value(type_error,GETTEXT("~S: argument ~S is not a hash table"));
  2184. obj = value1;
  2185. }
  2186. return obj;
  2187. }
  2188. LISPFUN(gethash,seclass_read,2,1,norest,nokey,0,NIL)
  2189. { /* (GETHASH key hashtable [default]), CLTL p. 284 */
  2190. var object ht = check_hashtable(STACK_1); /* hashtable argument */
  2191. var gcv_object_t* KVptr;
  2192. var gcv_object_t* Iptr;
  2193. /* search key STACK_2 in the hash-table: */
  2194. if (hash_lookup(ht,STACK_2,true,&KVptr,&Iptr)) { /* -> Value as value: */
  2195. VALUES2(KVptr[1], T); /* and T as the 2nd value */
  2196. skipSTACK(3);
  2197. } else { /* not found -> default or NIL as value */
  2198. var object def = popSTACK(); /* default */
  2199. VALUES2(!boundp(def) ? NIL : def,
  2200. NIL); /* NIL as the 2nd value */
  2201. skipSTACK(2);
  2202. }
  2203. }
  2204. LISPFUNN(puthash,3)
  2205. { /* (SYSTEM::PUTHASH key hashtable value) =
  2206. (SETF (GETHASH key hashtable) value), CLTL p. 284 */
  2207. STACK_1 = check_hashtable(STACK_1); /* hashtable argument */
  2208. var gcv_object_t* KVptr;
  2209. var gcv_object_t* Iptr;
  2210. /* search key STACK_2 in the hash-table: */
  2211. if (hash_lookup(STACK_1,STACK_2,true,&KVptr,&Iptr)) { /* -> replace value: */
  2212. VALUES1(KVptr[1] = popSTACK()); skipSTACK(2);
  2213. } else { /* not found -> make new entry: */
  2214. var object ht;
  2215. var object freelist;
  2216. hash_prepare_store(1,2); /* ht==STACK_1, obj==STACK_2 */
  2217. hash_store(STACK_2,STACK_0); /* make entry */
  2218. VALUES1(popSTACK()); /* value as value */
  2219. skipSTACK(2);
  2220. }
  2221. }
  2222. /* UP: Searches a key in a hash-table and returns the last value.
  2223. shifthash(ht,obj,value) == (SHIFTF (GETHASH obj ht) value)
  2224. > ht: hash-table
  2225. > obj: object
  2226. > value: new value
  2227. > allowgc: whether GC is allowed during hash lookup
  2228. (should be true if the hash-table has a user-defined test or
  2229. if the hash-table is not known to already contain a value for obj)
  2230. < result: old value
  2231. can trigger GC - if allowgc is true */
  2232. global /*maygc*/ object shifthash (object ht, object obj, object value, bool allowgc) {
  2233. GCTRIGGER_IF(allowgc, GCTRIGGER3(ht,obj,value));
  2234. var gcv_object_t* KVptr;
  2235. var gcv_object_t* Iptr;
  2236. pushSTACK(ht); pushSTACK(obj); pushSTACK(value); /* save args */
  2237. /* search key obj in the hash-table: */
  2238. if (hash_lookup(ht,obj,allowgc,&KVptr,&Iptr)) { /* found -> replace value: */
  2239. var object oldvalue = KVptr[1];
  2240. KVptr[1] = STACK_0; skipSTACK(3);
  2241. return oldvalue;
  2242. } else { /* not found -> build new entry: */
  2243. ASSERT(allowgc);
  2244. var object freelist;
  2245. hash_prepare_store(2,1); /* ht==STACK_2, obj==STACK_1 */
  2246. hash_store(STACK_1,STACK_0); /* build entry */
  2247. skipSTACK(3);
  2248. return NIL; /* default for the old value is NIL */
  2249. }
  2250. }
  2251. LISPFUNN(remhash,2)
  2252. { /* (REMHASH key hashtable), CLTL p. 284 */
  2253. STACK_0 = check_hashtable(STACK_0); /* hashtable argument */
  2254. var object key = STACK_1; /* key-argument */
  2255. var gcv_object_t* KVptr;
  2256. var gcv_object_t* Iptr;
  2257. /* search key in the hash-table: */
  2258. if (hash_lookup(STACK_0,key,true,&KVptr,&Iptr)) {
  2259. /* found -> drop from the hash-table: */
  2260. var object ht = STACK_0; skipSTACK(2);
  2261. var object kvtable = TheHashtable(ht)->ht_kvtable;
  2262. var object index = *Iptr; /* index in next-vector */
  2263. /* with KVptr = &TheHashedAlist(kvtable)->hal_data[3*index] */
  2264. set_break_sem_2(); /* protect from breaks */
  2265. *KVptr++ = leer; *KVptr++ = leer; /* empty key and value */
  2266. *Iptr = *KVptr; /* shorten "list" */
  2267. /* lengthen free-list: */
  2268. *KVptr = TheHashedAlist(kvtable)->hal_freelist;
  2269. TheHashedAlist(kvtable)->hal_freelist = index;
  2270. /* decrement COUNT : */
  2271. TheHashedAlist(kvtable)->hal_count = fixnum_inc(TheHashedAlist(kvtable)->hal_count,-1);
  2272. clr_break_sem_2(); /* allow breaks again */
  2273. /* shrink the hash-table for COUNT < MINCOUNT : */
  2274. if ( posfixnum_to_V(TheHashedAlist(kvtable)->hal_count)
  2275. < posfixnum_to_V(TheHashtable(ht)->ht_mincount)) {
  2276. /* shrink hash-table:
  2277. maxcount := (max (floor (/ maxcount rehash-size)) 1) */
  2278. pushSTACK(ht); /* save hashtable */
  2279. pushSTACK(TheHashtable(ht)->ht_maxcount);
  2280. pushSTACK(TheHashtable(ht)->ht_rehash_size); /* REHASH-SIZE (>1) */
  2281. funcall(L(slash),2); /* (/ maxcount rehash-size), is < maxcount */
  2282. pushSTACK(value1);
  2283. funcall(L(floor),1); /* (floor ...), an integer >=0, < maxcount */
  2284. var object maxcount = value1;
  2285. if (eq(maxcount,Fixnum_0))
  2286. maxcount = Fixnum_1; /* turn 0 into 1 */
  2287. resize(popSTACK(),maxcount); /* shrink table */
  2288. }
  2289. VALUES1(T);
  2290. } else { /* not found */
  2291. skipSTACK(2); VALUES1(NIL);
  2292. }
  2293. }
  2294. LISPFUNN(maphash,2)
  2295. { /* (MAPHASH function hashtable), CLTL p. 285 */
  2296. var object ht = check_hashtable(STACK_0); /* hashtable argument */
  2297. /* traverse the key-value-vector in reverse direction and
  2298. call the function for all key-value-pairs with key /= "leer" : */
  2299. var uintL index = 3*posfixnum_to_V(TheHashtable(ht)->ht_maxcount);
  2300. STACK_0 = TheHashtable(ht)->ht_kvtable; /* key-value-vector */
  2301. /* stack-layout: function, key-value-vector. */
  2302. while (index) {
  2303. index -= 3;
  2304. var gcv_object_t* KVptr = &TheHashedAlist(STACK_0)->hal_data[index];
  2305. if (!eq(KVptr[0],leer)) { /* key /= "leer" ? */
  2306. pushSTACK(KVptr[0]); /* key as the 1st argument */
  2307. pushSTACK(KVptr[1]); /* value as the 2nd argument */
  2308. funcall(STACK_(1+2),2); /* (FUNCALL function Key Value) */
  2309. }
  2310. }
  2311. skipSTACK(2);
  2312. VALUES1(NIL);
  2313. }
  2314. LISPFUNN(clrhash,1)
  2315. { /* (CLRHASH hashtable), CLTL p. 285 */
  2316. var object ht = check_hashtable(popSTACK()); /* hashtable argument */
  2317. clrhash(ht); /* empty table */
  2318. /* Shrink the hash-table when MINCOUNT > 0 : */
  2319. if (!eq(TheHashtable(ht)->ht_mincount,Fixnum_0))
  2320. ht = resize(ht,Fixnum_1); /* shrink to MAXCOUNT:=1 , so that MINCOUNT:=0 */
  2321. VALUES1(ht); /* hash-table as value */
  2322. }
  2323. LISPFUNNR(hash_table_count,1)
  2324. { /* (HASH-TABLE-COUNT hashtable), CLTL p. 285, CLtL2 p. 439 */
  2325. var object ht = check_hashtable(popSTACK()); /* hashtable argument */
  2326. var object count = TheHashedAlist(TheHashtable(ht)->ht_kvtable)->hal_count;
  2327. VALUES1(count); /* fixnum COUNT as value */
  2328. }
  2329. LISPFUNNR(hash_table_rehash_size,1)
  2330. { /* (HASH-TABLE-REHASH-SIZE hashtable), CLtL2 p. 441, dpANS p. 18-7 */
  2331. var object ht = check_hashtable(popSTACK()); /* hashtable argument */
  2332. VALUES1(TheHashtable(ht)->ht_rehash_size); /* short-float REHASH-SIZE */
  2333. }
  2334. LISPFUNNR(hash_table_rehash_threshold,1)
  2335. { /* (HASH-TABLE-REHASH-THRESHOLD hashtable), CLtL2 p. 441, dpANS p. 18-8 */
  2336. var object ht = check_hashtable(popSTACK()); /* hashtable argument */
  2337. /* As MAKE-HASH-TABLE ignores the :REHASH-THRESHOLD argument, the value
  2338. is irrelevant here and arbitrary. */
  2339. VALUES1(make_SF(0,SF_exp_mid+0,(bit(SF_mant_len)/2)*3)); /* 0.75s0 */
  2340. }
  2341. LISPFUNNR(hash_table_size,1)
  2342. { /* (HASH-TABLE-SIZE hashtable), CLtL2 p. 441, dpANS p. 18-9 */
  2343. var object ht = check_hashtable(popSTACK()); /* hashtable argument */
  2344. VALUES1(TheHashtable(ht)->ht_maxcount); /* Fixnum MAXCOUNT */
  2345. }
  2346. LISPFUNNR(hash_table_warn_if_needs_rehash_after_gc,1)
  2347. { /* (HASH-TABLE-WARN-IF-NEEDS-REHASH-AFTER-GC hashtable) */
  2348. var object ht = check_hashtable(popSTACK()); /* hashtable argument */
  2349. VALUES_IF(record_flags(TheHashtable(ht)) & htflags_warn_gc_rehash_B);
  2350. }
  2351. LISPFUNN(set_hash_table_warn_if_needs_rehash_after_gc,2)
  2352. { /* ((SETF HASH-TABLE-WARN-IF-NEEDS-REHASH-AFTER-GC) val hashtable) */
  2353. var object ht = check_hashtable(popSTACK()); /* hashtable argument */
  2354. var bool warn_p = !nullp(popSTACK());
  2355. if (warn_p)
  2356. record_flags_set(TheHashtable(ht),htflags_warn_gc_rehash_B);
  2357. else
  2358. record_flags_clr(TheHashtable(ht),htflags_warn_gc_rehash_B);
  2359. VALUES_IF(warn_p);
  2360. }
  2361. /* return the hash table symbol
  2362. or cons (test . hash) for user-defined ht_test
  2363. can trigger GC - for user-defined ht_test */
  2364. global maygc object hash_table_test (object ht) {
  2365. var uintB test_code = ht_test_code(record_flags(TheHashtable(ht)));
  2366. switch (test_code) {
  2367. case htflags_test_eq_B:
  2368. { return S(fasthash_eq); }
  2369. case htflags_test_eq_B | htflags_stablehash_B:
  2370. { return S(stablehash_eq); }
  2371. case htflags_test_eql_B:
  2372. { return S(fasthash_eql); }
  2373. case htflags_test_eql_B | htflags_stablehash_B:
  2374. { return S(stablehash_eql); }
  2375. case htflags_test_equal_B:
  2376. { return S(fasthash_equal); }
  2377. case htflags_test_equal_B | htflags_stablehash_B:
  2378. { return S(stablehash_equal); }
  2379. case htflags_test_equalp_B:
  2380. { return S(equalp); }
  2381. case bit(2): { /* user-defined ==> (test . hash) */
  2382. pushSTACK(ht);
  2383. var object ret = allocate_cons();
  2384. ht = popSTACK();
  2385. Car(ret) = TheHashtable(ht)->ht_test;
  2386. Cdr(ret) = TheHashtable(ht)->ht_hash;
  2387. /* should we do this at all? */
  2388. /*if (subrp(Car(ret))) Car(ret) = TheSubr(Car(ret))->name;
  2389. if (subrp(Cdr(ret))) Cdr(ret) = TheSubr(Cdr(ret))->name;*/
  2390. return ret;
  2391. }
  2392. default: NOTREACHED;
  2393. }
  2394. }
  2395. LISPFUNNF(hash_table_test,1)
  2396. { /* (HASH-TABLE-TEST hashtable), CLtL2 p. 441, dpANS p. 18-9 */
  2397. var object ht = check_hashtable(popSTACK()); /* hashtable argument */
  2398. VALUES1(hash_table_test(ht)); /* symbol as value */
  2399. }
  2400. /* (SYSTEM::FASTHASH-STABLE-P obj)
  2401. tests whether obj's FASTHASH-EQ hash code is stable across GCs. */
  2402. LISPFUNNF(fasthash_stable_p,1)
  2403. {
  2404. var object obj = popSTACK();
  2405. VALUES_IF(gcinvariant_hashcode1_p(obj));
  2406. }
  2407. /* (SYSTEM::STABLEHASH-STABLE-P obj)
  2408. tests whether obj's STABLEHASH-EQ hash code is stable across GCs. */
  2409. LISPFUNNR(stablehash_stable_p,1)
  2410. {
  2411. var object obj = popSTACK();
  2412. VALUES_IF(gcinvariant_hashcode1stable_p(obj));
  2413. }
  2414. /* auxiliary functions for WITH-HASH-TABLE-ITERATOR, CLTL2 p. 439:
  2415. (SYSTEM::HASH-TABLE-ITERATOR hashtable) returns an internal state
  2416. for iterating through a hash-table.
  2417. (SYSTEM::HASH-TABLE-ITERATE internal-state) iterates through a hash-table
  2418. by one, thereby changes internal-state and returns: 3 values
  2419. T, key, value of the next hash-table-entry resp. 1 value NIL at the end. */
  2420. LISPFUNNR(hash_table_iterator,1) {
  2421. var object ht = check_hashtable(STACK_0); /* hashtable argument */
  2422. /* An internal state consists of the key-value-vector and an index. */
  2423. STACK_0 = TheHashtable(ht)->ht_kvtable; /* key-value-vector */
  2424. var object maxcount = TheHashtable(ht)->ht_maxcount; /* maxcount */
  2425. var object state = allocate_cons();
  2426. Car(state) = popSTACK(); /* key-value-vector as car */
  2427. Cdr(state) = maxcount; /* maxcount as cdr */
  2428. VALUES1(state); /* state as value */
  2429. }
  2430. LISPFUNN(hash_table_iterate,1) {
  2431. var object state = popSTACK(); /* internal state */
  2432. if (consp(state)) { /* hopefully a cons */
  2433. var object table = Car(state); /* key-value-vector */
  2434. while (1) {
  2435. var uintL index = posfixnum_to_V(Cdr(state));
  2436. if (index==0) /* index=0 -> no more elements */
  2437. break;
  2438. Cdr(state) = fixnum_inc(Cdr(state),-1); /* decrement index */
  2439. var gcv_object_t* KVptr = &TheHashedAlist(table)->hal_data[3*index-3];
  2440. if (!eq(KVptr[0],leer)) { /* Key /= "leer" ? */
  2441. VALUES3(T,
  2442. KVptr[0], /* key as the 2nd value */
  2443. KVptr[1]); /* value as the 3rd value */
  2444. return;
  2445. }
  2446. }
  2447. }
  2448. VALUES1(NIL); return; /* 1 value NIL */
  2449. }
  2450. LISPFUNNR(hash_table_weak_p,1)
  2451. { /* (EXT:HASH-TABLE-WEAK-P ht) */
  2452. var object ht = check_hashtable(popSTACK()); /* hashtable argument */
  2453. VALUES1(hash_table_weak_type(ht));
  2454. }
  2455. LISPFUNN(set_hash_table_weak_p,2)
  2456. { /* ((SETF HASH-TABLE-WEAK-P) weak-p ht) */
  2457. STACK_0 = check_hashtable(STACK_0);
  2458. var object val = check_weak(STACK_1); /* weak-p */
  2459. var object ht = STACK_0; /* hashtable argument */
  2460. if (!eq(val,hash_table_weak_type(ht))) {
  2461. var uintL maxcount = posfixnum_to_V(TheHashtable(ht)->ht_maxcount);
  2462. var object new_kvt;
  2463. for (;;) {
  2464. new_kvt = allocate_kvt(val,maxcount);
  2465. /* Check whether the hash-table has not been resized during
  2466. allocate_kvt(). */
  2467. var uintL new_maxcount =
  2468. posfixnum_to_V(TheHashtable(STACK_0)->ht_maxcount);
  2469. if (maxcount == new_maxcount)
  2470. break;
  2471. maxcount = new_maxcount;
  2472. }
  2473. ht = STACK_0;
  2474. var object old_kvt = TheHashtable(ht)->ht_kvtable;
  2475. copy_mem_o(&TheHashedAlist(new_kvt)->hal_data[0],
  2476. &TheHashedAlist(old_kvt)->hal_data[0],
  2477. 3*maxcount);
  2478. TheHashedAlist(new_kvt)->hal_itable = TheHashedAlist(old_kvt)->hal_itable;
  2479. TheHashedAlist(new_kvt)->hal_count = TheHashedAlist(old_kvt)->hal_count;
  2480. TheHashedAlist(new_kvt)->hal_freelist = TheHashedAlist(old_kvt)->hal_freelist;
  2481. TheHashtable(ht)->ht_kvtable = new_kvt;
  2482. }
  2483. VALUES1(hash_table_weak_type(ht)); skipSTACK(2);
  2484. }
  2485. LISPFUNN(class_gethash,2)
  2486. {/* (CLOS::CLASS-GETHASH ht object) is like (GETHASH (CLASS-OF object) ht). */
  2487. var object ht = check_hashtable(STACK_1); /* hashtable argument */
  2488. C_class_of(); /* value1 := (CLASS-OF object) */
  2489. var object clas = value1;
  2490. if (!ht_validp(TheHashtable(ht))) /* hash-table must still be reorganized */
  2491. ht = rehash(ht);
  2492. {
  2493. var uint32 code = /* calculate hashcode1stable of the class */
  2494. posfixnum_to_V(TheClass(clas)->hashcode);
  2495. var uintL hashindex;
  2496. divu_3232_3232(code,TheHashtable(ht)->ht_size, (void),hashindex = );
  2497. var object kvtable = TheHashtable(ht)->ht_kvtable;
  2498. var gcv_object_t* Nptr = /* pointer to the current entry */
  2499. &TheSvector(TheHashedAlist(kvtable)->hal_itable)->data[hashindex];
  2500. var gcv_object_t* kvt_data = TheHashedAlist(kvtable)->hal_data;
  2501. while (!eq(*Nptr,nix)) { /* track "list" : "list" finished -> not found */
  2502. var uintL index = posfixnum_to_V(*Nptr); /* next index */
  2503. var gcv_object_t* KVptr = /* pointer to entries in key-value-vector */
  2504. kvt_data + 3*index;
  2505. /* compare key */
  2506. if (eq(KVptr[0],clas)) {
  2507. /* found */
  2508. VALUES2(KVptr[1], T); goto done;
  2509. }
  2510. Nptr = &KVptr[2]; /* pointer to index of next entry */
  2511. }
  2512. /* not found */
  2513. VALUES2(NIL, NIL); /* NIL as the 2nd value */
  2514. }
  2515. done:
  2516. skipSTACK(1);
  2517. }
  2518. /* (CLOS::CLASS-TUPLE-GETHASH ht object1 ... objectn)
  2519. is like (GETHASH (funcall (hash-tuple-function n) class1 ... classn) ht)
  2520. with classi = (CLASS-OF objecti).
  2521. Definition: n>0, ht is a STABLEHASH-EQUAL-hashtable and
  2522. (hash-tuple-function n) is defined in clos.lisp .
  2523. This function is the core of the dispatch for generic functions. It has to
  2524. be fast and must not cons.
  2525. For 1 < n <= 16,
  2526. (hash-tuple-function n ...) =
  2527. (cons (hash-tuple-function n1 ...) (hash-tuple-function n2 ...)) */
  2528. local const uintC tuple_half_1 [17] = {0,0,1,1,2,2,2,3,4,4,4,4,4,5,6,7,8};
  2529. local const uintC tuple_half_2 [17] = {0,0,1,2,2,3,4,4,4,5,6,7,8,8,8,8,8};
  2530. /* auxiliary function: hashcode of a series of atoms, as if they were
  2531. consed together via (hash-tuple-function n) : */
  2532. local uint32 hashcode_tuple (uintC n, const gcv_object_t* args_pointer,
  2533. uintC depth) {
  2534. if (n==1) {
  2535. var object clas = Next(args_pointer);
  2536. return posfixnum_to_V(TheClass(clas)->hashcode); /* hashcode3stable_atom for classes */
  2537. } else if (n<=16) {
  2538. var uintC n1 = tuple_half_1[n];
  2539. var uintC n2 = tuple_half_2[n]; /* n1 + n2 = n */
  2540. var uint32 code1 = hashcode_tuple(n1,args_pointer,depth+1);
  2541. var uint32 code2 = hashcode_tuple(n2,args_pointer STACKop -(uintP)n1,
  2542. depth+1);
  2543. switch (depth) {
  2544. case 0: code1 = rotate_left(16,code1); break;
  2545. case 1: code1 = rotate_left(7,code1); break; /* cf. hashcode3_cons3 */
  2546. case 2: code1 = rotate_left(5,code1); break; /* cf. hashcode3_cons2 */
  2547. case 3: code1 = rotate_left(3,code1); break; /* cf. hashcode3_cons1 */
  2548. default: NOTREACHED;
  2549. }
  2550. return code1 ^ code2;
  2551. } else { /* n>16, depth=0 */
  2552. var uint32 code1 = hashcode_tuple(8,args_pointer,1);
  2553. var uint32 code2 = hashcode_tuple(4,args_pointer STACKop -8,2);
  2554. var uint32 code3 = hashcode_tuple(2,args_pointer STACKop -12,3);
  2555. var uint32 code4 = hashcode_tuple(1,args_pointer STACKop -14,4);
  2556. var uint32 code = 1; /* cf. hashcode3_cons0 */
  2557. code = rotate_left(3,code4) ^ code; /* cf. hashcode3_cons1 */
  2558. code = rotate_left(5,code3) ^ code; /* cf. hashcode3_cons2 */
  2559. code = rotate_left(7,code2) ^ code; /* cf. hashcode3_cons3 */
  2560. code = rotate_left(16,code1) ^ code;
  2561. return code;
  2562. }
  2563. }
  2564. /* auxiliary function: Comparison of an object with a series of atoms, as if
  2565. they were consed together via (hash-tuple-function n) : */
  2566. local bool equal_tuple (object obj, uintC n, const gcv_object_t* args_pointer) {
  2567. if (n==1) {
  2568. if (eq(obj,Next(args_pointer)))
  2569. return true;
  2570. else
  2571. return false;
  2572. } else if (n<=16) {
  2573. if (consp(obj)) {
  2574. var uintC n1 = tuple_half_1[n];
  2575. var uintC n2 = tuple_half_2[n]; /* n1 + n2 = n */
  2576. if (equal_tuple(Car(obj),n1,args_pointer)
  2577. && equal_tuple(Cdr(obj),n2,args_pointer STACKop -(uintP)n1)
  2578. )
  2579. return true;
  2580. }
  2581. return false;
  2582. } else { /* n>16 */
  2583. if (consp(obj) && equal_tuple(Car(obj),8,args_pointer)) {
  2584. obj = Cdr(obj);
  2585. if (consp(obj) && equal_tuple(Car(obj),4,args_pointer STACKop -8)) {
  2586. obj = Cdr(obj);
  2587. if (consp(obj) && equal_tuple(Car(obj),2,args_pointer STACKop -12)) {
  2588. obj = Cdr(obj);
  2589. n-=14; args_pointer skipSTACKop -14;
  2590. /* compare obj with a list of additional atoms: */
  2591. dotimespC(n,n, {
  2592. if (!(consp(obj) && eq(Car(obj),Next(args_pointer))))
  2593. return false;
  2594. obj = Cdr(obj); args_pointer skipSTACKop -1;
  2595. });
  2596. if (nullp(obj))
  2597. /* comparison yields true */
  2598. return true;
  2599. }
  2600. }
  2601. }
  2602. return false;
  2603. }
  2604. }
  2605. LISPFUN(class_tuple_gethash,seclass_default,2,0,rest,nokey,0,NIL) {
  2606. argcount++; rest_args_pointer skipSTACKop 1; /* arguments: ht {object}+ */
  2607. /* first apply CLASS-OF to each argument: */
  2608. {
  2609. var gcv_object_t* arg_pointer = rest_args_pointer;
  2610. var uintC count;
  2611. dotimespC(count,argcount, {
  2612. pushSTACK(Next(arg_pointer)); C_class_of(); /* (CLASS-OF arg) */
  2613. NEXT(arg_pointer) = value1; /* =: arg */
  2614. });
  2615. }
  2616. var object ht = check_hashtable(Before(rest_args_pointer));
  2617. if (!ht_validp(TheHashtable(ht))) /* hash-table must still be reorganized */
  2618. ht = rehash(ht);
  2619. {
  2620. var uint32 code = /* calculate hashcode of the cons-tree */
  2621. hashcode_tuple(argcount,rest_args_pointer,0);
  2622. var uintL hashindex;
  2623. divu_3232_3232(code,TheHashtable(ht)->ht_size, (void),hashindex = );
  2624. var object kvtable = TheHashtable(ht)->ht_kvtable;
  2625. var gcv_object_t* Nptr = /* pointer to the current entry */
  2626. &TheSvector(TheHashedAlist(kvtable)->hal_itable)->data[hashindex];
  2627. var gcv_object_t* kvt_data = TheHashedAlist(kvtable)->hal_data;
  2628. while (!eq(*Nptr,nix)) { /* track "list" : "list" finished -> not found */
  2629. var uintL index = posfixnum_to_V(*Nptr); /* next index */
  2630. var gcv_object_t* KVptr = /* pointer to entries in key-value-vector */
  2631. kvt_data + 3*index;
  2632. if (equal_tuple(KVptr[0],argcount,rest_args_pointer)) { /* compare key */
  2633. /* found */
  2634. VALUES1(KVptr[1]); goto done; /* Value as value */
  2635. }
  2636. Nptr = &KVptr[2]; /* pointer to index of next entry */
  2637. }
  2638. }
  2639. /* not found */
  2640. VALUES1(NIL);
  2641. done:
  2642. set_args_end_pointer(rest_args_pointer STACKop 1); /* clean up STACK */
  2643. }
  2644. /* UP: Calculates a portable EQUAL-hashcode of an object.
  2645. sxhash(obj)
  2646. It is valid only until the next modification of the object.
  2647. (equal X Y) implies (= (sxhash X) (sxhash Y)).
  2648. > obj: an object
  2649. < result: hashcode, a 32-bit-number */
  2650. local uint32 sxhash (object obj);
  2651. /* auxiliary functions for known type:
  2652. atom -> fall differentiation by type */
  2653. local uint32 sxhash_atom (object obj) {
  2654. #ifdef TYPECODES
  2655. switch (typecode(obj)) /* per type */
  2656. #else
  2657. if (orecordp(obj)) {
  2658. if (Record_type(obj) < rectype_longlimit)
  2659. goto case_orecord;
  2660. else
  2661. goto case_lrecord;
  2662. } else if (consp(obj))
  2663. goto case_cons;
  2664. else if (charp(obj))
  2665. goto case_char;
  2666. else if (fixnump(obj))
  2667. goto case_fixnum;
  2668. else if (short_float_p(obj))
  2669. goto case_sfloat;
  2670. else if (immsubrp(obj))
  2671. goto case_subr;
  2672. else if (machinep(obj))
  2673. goto case_machine;
  2674. else if (small_read_label_p(obj) || systemp(obj))
  2675. goto case_system;
  2676. else switch (0)
  2677. #endif
  2678. {
  2679. case_symbol: /* symbol */
  2680. /* utilize printname
  2681. (not the home-package, because it is changed on UNINTERN) */
  2682. return hashcode_string(Symbol_name(obj))+0x339B0E4CUL;
  2683. case_cons:
  2684. default:
  2685. /* address may not be used, only utilize the type */
  2686. #ifdef TYPECODES
  2687. return highlow32(typecode(obj),0xDABE); /*typeinfo*2^16+identification*/
  2688. #else
  2689. return highlow32((as_oint(obj)>>oint_type_shift)&(oint_type_mask>>oint_type_shift),0xDABE); /* typeinfo*2^16+identification */
  2690. #endif
  2691. case_bvector: /* bit-vector */
  2692. case_b2vector: /* 2bit-vector */
  2693. case_b4vector: /* 4bit-vector */
  2694. case_b8vector: /* 8bit-vector */
  2695. case_b16vector: /* 16bit-vector */
  2696. case_b32vector: /* 32bit-vector */
  2697. /* bit-vector-content */
  2698. return hashcode_bvector(obj);
  2699. case_string: /* string */
  2700. /* string-content */
  2701. return hashcode_string(obj);
  2702. case_svector: /* simple-vector */
  2703. /* only utilize the length */
  2704. return Svector_length(obj) + 0x4ECD0A9FUL;
  2705. case_ovector: /* (vector t) */
  2706. case_mdarray: /* common array */
  2707. /* multi-dimensional array -> utilize only rank */
  2708. return Iarray_rank(obj) + 0xAAFAFAAEUL;
  2709. case_structure: /* structure */
  2710. /* utilize only structure-type (Liste (name_1 name_2 ... name_n)) */
  2711. check_SP();
  2712. return sxhash(TheStructure(obj)->structure_types) + 0xAD2CD2AEUL;
  2713. case_stream: /* stream */
  2714. /* utilize only streamtype */
  2715. return TheStream(obj)->strmtype + 0x3DAEAE55UL;
  2716. {var uint32 bish_code;
  2717. case_closure: /* closure */
  2718. if (Closure_instancep(obj)) goto instance_only_class;
  2719. /* utilize all elements ?? */
  2720. bish_code = 0xB0DD939EUL; goto record_all;
  2721. case_orecord: { /* OtherRecord */
  2722. /* utilize record-type, also:
  2723. package: utilize package-name verwerten (not quite OK, as a
  2724. package can be renamed with RENAME-PACKAGE!)
  2725. pathname, byte, loadtimeeval: utilize all components
  2726. hash-table, readtable, random-state, symbol-macro: nothing else */
  2727. var sintB rectype = Record_type(obj);
  2728. switch (rectype) {
  2729. case_Rectype_Symbol_above;
  2730. case_Rectype_bvector_above;
  2731. case_Rectype_b2vector_above;
  2732. case_Rectype_b4vector_above;
  2733. case_Rectype_b8vector_above;
  2734. case_Rectype_b16vector_above;
  2735. case_Rectype_b32vector_above;
  2736. case_Rectype_string_above;
  2737. case_Rectype_Svector_above;
  2738. case_Rectype_ovector_above;
  2739. case_Rectype_mdarray_above;
  2740. case_Rectype_Structure_above;
  2741. case_Rectype_Stream_above;
  2742. case_Rectype_Closure_above;
  2743. case_Rectype_Instance_above;
  2744. case_Rectype_Bignum_above;
  2745. case_Rectype_Ffloat_above;
  2746. case_Rectype_Dfloat_above;
  2747. case_Rectype_Lfloat_above;
  2748. case_Rectype_Ratio_above;
  2749. case_Rectype_Complex_above;
  2750. case_Rectype_Subr_above;
  2751. default: ;
  2752. }
  2753. bish_code = 0xB04D939EUL + rectype;
  2754. switch (rectype) {
  2755. case Rectype_Package: { /* package */
  2756. /* utilize package-name */
  2757. var uint32 next_code = hashcode_string(ThePackage(obj)->pack_name);
  2758. return rotate_left(1,next_code) + bish_code;
  2759. }
  2760. case Rectype_Fsubr: /* fsubr */
  2761. /* utilize name */
  2762. check_SP(); return sxhash(TheFsubr(obj)->name) + 0xFF3319BAUL;
  2763. case Rectype_Pathname: /* pathname */
  2764. #ifdef LOGICAL_PATHNAMES
  2765. case Rectype_Logpathname: /* pathname */
  2766. #endif
  2767. case Rectype_Byte: /* byte */
  2768. case Rectype_Loadtimeeval: /* loadtimeeval */
  2769. goto record_all;
  2770. default:
  2771. return bish_code;
  2772. }
  2773. }
  2774. record_all:
  2775. /* record, in which all elements can be utilized */
  2776. check_SP();
  2777. {
  2778. var gcv_object_t* ptr = &TheRecord(obj)->recdata[0];
  2779. var uintC count = SXrecord_length(obj);
  2780. dotimespC(count,count, {
  2781. /* combine hashcode of the next component: */
  2782. var uint32 next_code = sxhash(*ptr++);
  2783. bish_code = misch(bish_code,next_code);
  2784. });
  2785. return bish_code;
  2786. }
  2787. }
  2788. instance_only_class:
  2789. case_instance: { /* instance */
  2790. /* utilize only the class */
  2791. var object obj_forwarded = obj;
  2792. instance_un_realloc(obj_forwarded);
  2793. /*instance_update(obj,obj_forwarded); - not needed since we don't access a slot */
  2794. var object cv = TheInstance(obj_forwarded)->inst_class_version;
  2795. var object objclass = TheClassVersion(cv)->cv_newest_class;
  2796. var object objclassname = TheClass(objclass)->classname;
  2797. return sxhash(objclassname) + 0x61EFA249;
  2798. }
  2799. case_lrecord: /* Long-Record */
  2800. /* utilize record-type and length */
  2801. return 0x8CAA9057UL + (Record_type(obj) << 24) + Lrecord_length(obj);
  2802. case_char: /* character */
  2803. /* take EQ-hashcode (for characters EQUAL == EQL == EQ) */
  2804. return hashcode1(obj);
  2805. case_subr: /* SUBR */
  2806. /* utilize name */
  2807. check_SP(); return sxhash(TheSubr(obj)->name) + 0xFF3319BAUL;
  2808. case_machine: /* machine-pointer */
  2809. case_system: /* frame-pointer, small-read-label, system */
  2810. /* utilize address */
  2811. return hashcode1(obj);
  2812. /* numbers: according to content, like with EQL */
  2813. case_fixnum: /* fixnum */
  2814. return hashcode_fixnum(obj);
  2815. case_bignum: /* bignum */
  2816. return hashcode_bignum(obj);
  2817. case_sfloat: /* short-float */
  2818. return hashcode_sfloat(obj);
  2819. case_ffloat: /* single-float */
  2820. return hashcode_ffloat(obj);
  2821. case_dfloat: /* double-float */
  2822. return hashcode_dfloat(obj);
  2823. case_lfloat: /* Long-Float */
  2824. return hashcode_lfloat(obj);
  2825. case_ratio: { /* ratio */
  2826. /* hash both components, mix */
  2827. var uint32 code1 = sxhash(TheRatio(obj)->rt_num);
  2828. var uint32 code2 = sxhash(TheRatio(obj)->rt_den);
  2829. return misch(code1,code2);
  2830. }
  2831. case_complex: { /* complex */
  2832. /* hash both components, mix */
  2833. var uint32 code1 = sxhash(TheComplex(obj)->c_real);
  2834. var uint32 code2 = sxhash(TheComplex(obj)->c_imag);
  2835. return misch(code1,code2);
  2836. }
  2837. }
  2838. }
  2839. local uint32 sxhash (object obj)
  2840. { return hashcode_tree(obj,sxhash_atom); }
  2841. LISPFUNN(sxhash,1)
  2842. { /* (SXHASH object), CLTL p. 285 */
  2843. var uint32 sx = sxhash(popSTACK());
  2844. /* ANSI CL (SXHASH doc):
  2845. For any two objects, x and y, both of which are bit vectors,
  2846. characters, conses, numbers, pathnames, strings, or symbols, and which
  2847. are similar, (sxhash x) and (sxhash y) yield the same mathematical
  2848. value even if x and y exist in different Lisp images of the same
  2849. implementation.
  2850. This might be interpreted - assuming that CLISP on Tru64 and CLISP on Win32
  2851. are the same implementations - that (SXHASH (1- (ASH 1 32))) should return
  2852. the same value both on 32-bit platforms (where 4294967295 is a bignum)
  2853. and on 64-bit platforms (where is is a fixnum).
  2854. On 32-bit platforms, hashcode_bignum() is used (returns 3 ==> 3).
  2855. On 64-bit platforms, hashcode_fixnum() is used (returns 4294967175 ==> 135).
  2856. Therefore, limiting ourselves to 24 bits on all platforms
  2857. does not buy us anything anyway. */
  2858. #if oint_data_len >= 32
  2859. VALUES1(fixnum(sx));
  2860. #elif oint_data_len >= 24
  2861. sx = sx % 0xFFFFFF;
  2862. VALUES1(fixnum(sx));
  2863. #else
  2864. #error "sxhash results do not fit in a fixnum"
  2865. #endif
  2866. }