LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 #include "runtime.h" | 5 #include "runtime.h" |
6 #include "hashmap.h" | 6 #include "hashmap.h" |
7 #include "type.h" | 7 #include "type.h" |
8 | 8 |
9 struct Hmap { /* a hash table; initialize with hash_init() */ | 9 struct Hmap { /* a hash table; initialize with hash_init() */ |
10 uint32 count; /* elements in table - must be first */ | 10 uint32 count; /* elements in table - must be first */ |
11 » uint32 datasize; /* amount of data to store in entry */ | 11 » uint8 datasize; /* amount of data to store in entry */ |
12 uint8 max_power; /* max power of 2 to create sub-tables */ | 12 uint8 max_power; /* max power of 2 to create sub-tables */ |
13 » uint8 indirectval;» /* storing pointers to values */ | 13 » uint8 indirect;»/* storing pointers to keys and/or values */ |
14 » uint32 valoff;» /* offset of value in key+value data block */ | 14 » uint8 valoff;» /* offset of value in key+value data block */ |
15 int32 changes; /* inc'ed whenever a subtable is created/grown */ | 15 int32 changes; /* inc'ed whenever a subtable is created/grown */ |
16 uintptr hash0; /* hash seed */ | 16 uintptr hash0; /* hash seed */ |
17 struct hash_subtable *st; /* first-level table */ | 17 struct hash_subtable *st; /* first-level table */ |
18 }; | 18 }; |
19 | 19 |
20 struct hash_entry { | 20 struct hash_entry { |
21 hash_hash_t hash; /* hash value of data */ | 21 hash_hash_t hash; /* hash value of data */ |
22 byte data[1]; /* user data has "datasize" bytes */ | 22 byte data[1]; /* user data has "datasize" bytes */ |
23 }; | 23 }; |
24 | 24 |
25 struct hash_subtable { | 25 struct hash_subtable { |
26 uint8 power; /* bits used to index this table */ | 26 uint8 power; /* bits used to index this table */ |
27 uint8 used; /* bits in hash used before reaching this table */ | 27 uint8 used; /* bits in hash used before reaching this table */ |
| 28 uint8 datasize; /* bytes of client data in an entry */ |
28 uint8 max_probes; /* max number of probes when searching */ | 29 uint8 max_probes; /* max number of probes when searching */ |
29 int16 limit_bytes; /* max_probes * (datasize+sizeof (hash_hash_t
)) */ | 30 int16 limit_bytes; /* max_probes * (datasize+sizeof (hash_hash_t
)) */ |
30 uint32 datasize; /* bytes of client data in an entry */ | |
31 struct hash_entry *last; /* points to last element of entry[] */ | 31 struct hash_entry *last; /* points to last element of entry[] */ |
32 struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsi
ze bytes */ | 32 struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsi
ze bytes */ |
33 }; | 33 }; |
34 | 34 |
35 #define HASH_DATA_EQ(eq, t, h,x,y) ((eq)=0, (*t->key->alg->equal) (&(eq), t->key
->size, (x), (y)), (eq)) | 35 #define HASH_DATA_EQ(eq, t, h,x,y) ((eq)=0, (*t->key->alg->equal) (&(eq), t->key
->size, (x), (y)), (eq)) |
36 | 36 |
37 #define HASH_REHASH 0x2 /* an internal flag */ | 37 #define HASH_REHASH 0x2 /* an internal flag */ |
38 /* the number of bits used is stored in the flags word too */ | 38 /* the number of bits used is stored in the flags word too */ |
39 #define HASH_USED(x) ((x) >> 2) | 39 #define HASH_USED(x) ((x) >> 2) |
40 #define HASH_MAKE_USED(x) ((x) << 2) | 40 #define HASH_MAKE_USED(x) ((x) << 2) |
41 | 41 |
42 #define HASH_LOW 6 | 42 #define HASH_LOW 6 |
43 #define HASH_ONE (((hash_hash_t)1) << HASH_LOW) | 43 #define HASH_ONE (((hash_hash_t)1) << HASH_LOW) |
44 #define HASH_MASK (HASH_ONE - 1) | 44 #define HASH_MASK (HASH_ONE - 1) |
45 #define HASH_ADJUST(x) (((x) < HASH_ONE) << HASH_LOW) | 45 #define HASH_ADJUST(x) (((x) < HASH_ONE) << HASH_LOW) |
46 | 46 |
47 #define HASH_BITS (sizeof (hash_hash_t) * 8) | 47 #define HASH_BITS (sizeof (hash_hash_t) * 8) |
48 | 48 |
49 #define HASH_SUBHASH HASH_MASK | 49 #define HASH_SUBHASH HASH_MASK |
50 #define HASH_NIL 0 | 50 #define HASH_NIL 0 |
51 #define HASH_NIL_MEMSET 0 | 51 #define HASH_NIL_MEMSET 0 |
52 | 52 |
53 #define HASH_OFFSET(base, byte_offset) \ | 53 #define HASH_OFFSET(base, byte_offset) \ |
54 ((struct hash_entry *) (((byte *) (base)) + (byte_offset))) | 54 ((struct hash_entry *) (((byte *) (base)) + (byte_offset))) |
55 | 55 |
56 #define HASH_MAX_PROBES 15 /* max entries to probe before rehashing */ | 56 #define HASH_MAX_PROBES 15 /* max entries to probe before rehashing */ |
| 57 |
| 58 // Bit masks for Hmap indirect field. |
| 59 #define HASH_INDIRECT_KEY 1 |
| 60 #define HASH_INDIRECT_VAL 2 |
57 | 61 |
58 /* return a hash layer with 2**power empty entries */ | 62 /* return a hash layer with 2**power empty entries */ |
59 static struct hash_subtable * | 63 static struct hash_subtable * |
60 hash_subtable_new (Hmap *h, int32 power, int32 used) | 64 hash_subtable_new (Hmap *h, int32 power, int32 used) |
61 { | 65 { |
62 int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); | 66 int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); |
63 int32 bytes = elemsize << power; | 67 int32 bytes = elemsize << power; |
64 struct hash_subtable *st; | 68 struct hash_subtable *st; |
65 int32 limit_bytes = HASH_MAX_PROBES * elemsize; | 69 int32 limit_bytes = HASH_MAX_PROBES * elemsize; |
66 int32 max_probes = HASH_MAX_PROBES; | 70 int32 max_probes = HASH_MAX_PROBES; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 } | 104 } |
101 *max_power = 12; | 105 *max_power = 12; |
102 } | 106 } |
103 | 107 |
104 static void | 108 static void |
105 hash_init (Hmap *h, int32 datasize, int64 hint) | 109 hash_init (Hmap *h, int32 datasize, int64 hint) |
106 { | 110 { |
107 int32 init_power; | 111 int32 init_power; |
108 int32 max_power; | 112 int32 max_power; |
109 | 113 |
110 assert(datasize >= 0); | |
111 assert(datasize + offsetof(struct hash_entry, data[0]) <= 0x7fffffff); | |
112 if(datasize < sizeof (void *)) | 114 if(datasize < sizeof (void *)) |
113 datasize = sizeof (void *); | 115 datasize = sizeof (void *); |
114 datasize = runtime·rnd(datasize, sizeof (void *)); | 116 datasize = runtime·rnd(datasize, sizeof (void *)); |
115 init_sizes (hint, &init_power, &max_power); | 117 init_sizes (hint, &init_power, &max_power); |
116 h->datasize = datasize; | 118 h->datasize = datasize; |
117 h->max_power = max_power; | 119 h->max_power = max_power; |
118 assert (h->datasize == datasize); | 120 assert (h->datasize == datasize); |
119 assert (h->max_power == max_power); | 121 assert (h->max_power == max_power); |
120 assert (sizeof (void *) <= h->datasize || h->max_power == 255); | 122 assert (sizeof (void *) <= h->datasize || h->max_power == 255); |
121 h->count = 0; | 123 h->count = 0; |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 static int32 | 263 static int32 |
262 hash_lookup (MapType *t, Hmap *h, void *data, void **pres) | 264 hash_lookup (MapType *t, Hmap *h, void *data, void **pres) |
263 { | 265 { |
264 int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); | 266 int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); |
265 hash_hash_t hash; | 267 hash_hash_t hash; |
266 struct hash_subtable *st = h->st; | 268 struct hash_subtable *st = h->st; |
267 int32 used = 0; | 269 int32 used = 0; |
268 hash_hash_t e_hash; | 270 hash_hash_t e_hash; |
269 struct hash_entry *e; | 271 struct hash_entry *e; |
270 struct hash_entry *end_e; | 272 struct hash_entry *end_e; |
| 273 bool indirectkey; |
271 bool eq; | 274 bool eq; |
272 ········ | 275 ········ |
273 hash = h->hash0; | 276 hash = h->hash0; |
274 (*t->key->alg->hash) (&hash, t->key->size, data); | 277 (*t->key->alg->hash) (&hash, t->key->size, data); |
275 hash &= ~HASH_MASK; | 278 hash &= ~HASH_MASK; |
276 hash += HASH_ADJUST (hash); | 279 hash += HASH_ADJUST (hash); |
277 for (;;) { | 280 for (;;) { |
278 int32 shift = HASH_BITS - (st->power + used); | 281 int32 shift = HASH_BITS - (st->power + used); |
279 int32 index_mask = (1 << st->power) - 1; | 282 int32 index_mask = (1 << st->power) - 1; |
280 int32 i = (hash >> shift) & index_mask; /* i is the natural p
osition of hash */ | 283 int32 i = (hash >> shift) & index_mask; /* i is the natural p
osition of hash */ |
281 | 284 |
282 e = HASH_OFFSET (st->entry, i * elemsize); /* e points to elemen
t i */ | 285 e = HASH_OFFSET (st->entry, i * elemsize); /* e points to elemen
t i */ |
283 e_hash = e->hash; | 286 e_hash = e->hash; |
284 if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable *
/ | 287 if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable *
/ |
285 break; | 288 break; |
286 } | 289 } |
287 used += st->power; | 290 used += st->power; |
288 st = *(struct hash_subtable **)e->data; | 291 st = *(struct hash_subtable **)e->data; |
289 } | 292 } |
290 end_e = HASH_OFFSET (e, st->limit_bytes); | 293 end_e = HASH_OFFSET (e, st->limit_bytes); |
291 while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) { | 294 while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) { |
292 e = HASH_OFFSET (e, elemsize); | 295 e = HASH_OFFSET (e, elemsize); |
293 } | 296 } |
| 297 indirectkey = h->indirect & HASH_INDIRECT_KEY; |
294 while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) { | 298 while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) { |
295 » » if (HASH_DATA_EQ (eq, t, h, data, e->data)) { /* a match */ | 299 » » void *k = e->data; |
| 300 » » if (indirectkey) |
| 301 » » » k = *(void**)k; |
| 302 » » if (HASH_DATA_EQ (eq, t, h, data, k)) { /* a match */ |
296 *pres = e->data; | 303 *pres = e->data; |
297 return (1); | 304 return (1); |
298 } | 305 } |
299 e = HASH_OFFSET (e, elemsize); | 306 e = HASH_OFFSET (e, elemsize); |
300 } | 307 } |
301 USED(e_hash); | 308 USED(e_hash); |
302 *pres = 0; | 309 *pres = 0; |
303 return (0); | 310 return (0); |
304 } | 311 } |
305 | 312 |
306 static int32 | 313 static int32 |
307 hash_remove (MapType *t, Hmap *h, void *data) | 314 hash_remove (MapType *t, Hmap *h, void *data) |
308 { | 315 { |
309 int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); | 316 int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); |
310 hash_hash_t hash; | 317 hash_hash_t hash; |
311 struct hash_subtable *st = h->st; | 318 struct hash_subtable *st = h->st; |
312 int32 used = 0; | 319 int32 used = 0; |
313 hash_hash_t e_hash; | 320 hash_hash_t e_hash; |
314 struct hash_entry *e; | 321 struct hash_entry *e; |
315 struct hash_entry *end_e; | 322 struct hash_entry *end_e; |
316 bool eq; | 323 bool eq; |
| 324 bool indirectkey; |
317 | 325 |
318 hash = h->hash0; | 326 hash = h->hash0; |
319 (*t->key->alg->hash) (&hash, t->key->size, data); | 327 (*t->key->alg->hash) (&hash, t->key->size, data); |
320 hash &= ~HASH_MASK; | 328 hash &= ~HASH_MASK; |
321 hash += HASH_ADJUST (hash); | 329 hash += HASH_ADJUST (hash); |
322 for (;;) { | 330 for (;;) { |
323 int32 shift = HASH_BITS - (st->power + used); | 331 int32 shift = HASH_BITS - (st->power + used); |
324 int32 index_mask = (1 << st->power) - 1; | 332 int32 index_mask = (1 << st->power) - 1; |
325 int32 i = (hash >> shift) & index_mask; /* i is the natural p
osition of hash */ | 333 int32 i = (hash >> shift) & index_mask; /* i is the natural p
osition of hash */ |
326 | 334 |
327 e = HASH_OFFSET (st->entry, i * elemsize); /* e points to elemen
t i */ | 335 e = HASH_OFFSET (st->entry, i * elemsize); /* e points to elemen
t i */ |
328 e_hash = e->hash; | 336 e_hash = e->hash; |
329 if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable *
/ | 337 if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable *
/ |
330 break; | 338 break; |
331 } | 339 } |
332 used += st->power; | 340 used += st->power; |
333 st = *(struct hash_subtable **)e->data; | 341 st = *(struct hash_subtable **)e->data; |
334 } | 342 } |
335 end_e = HASH_OFFSET (e, st->limit_bytes); | 343 end_e = HASH_OFFSET (e, st->limit_bytes); |
336 while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) { | 344 while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) { |
337 e = HASH_OFFSET (e, elemsize); | 345 e = HASH_OFFSET (e, elemsize); |
338 } | 346 } |
| 347 indirectkey = h->indirect & HASH_INDIRECT_KEY; |
339 while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) { | 348 while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) { |
340 » » if (HASH_DATA_EQ (eq, t, h, data, e->data)) { /* a match */ | 349 » » void *k = e->data; |
341 » » » if (h->indirectval) | 350 » » if (indirectkey) |
| 351 » » » k = *(void**)k; |
| 352 » » if (HASH_DATA_EQ (eq, t, h, data, k)) { /* a match */ |
| 353 » » » if (indirectkey) |
| 354 » » » » free (k); |
| 355 » » » if (h->indirect & HASH_INDIRECT_VAL) |
342 free (*(void**)((byte*)e->data + h->valoff)); | 356 free (*(void**)((byte*)e->data + h->valoff)); |
343 hash_remove_n (st, e, 1); | 357 hash_remove_n (st, e, 1); |
344 h->count--; | 358 h->count--; |
345 return (1); | 359 return (1); |
346 } | 360 } |
347 e = HASH_OFFSET (e, elemsize); | 361 e = HASH_OFFSET (e, elemsize); |
348 } | 362 } |
349 USED(e_hash); | 363 USED(e_hash); |
350 return (0); | 364 return (0); |
351 } | 365 } |
352 | 366 |
353 static int32 | 367 static int32 |
354 hash_insert_internal (MapType *t, struct hash_subtable **pst, int32 flags, hash_
hash_t hash, | 368 hash_insert_internal (MapType *t, struct hash_subtable **pst, int32 flags, hash_
hash_t hash, |
355 Hmap *h, void *data, void **pres) | 369 Hmap *h, void *data, void **pres) |
356 { | 370 { |
357 int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); | 371 int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); |
358 bool eq; | 372 bool eq; |
| 373 bool indirectkey; |
359 | 374 |
360 if ((flags & HASH_REHASH) == 0) { | 375 if ((flags & HASH_REHASH) == 0) { |
361 hash += HASH_ADJUST (hash); | 376 hash += HASH_ADJUST (hash); |
362 hash &= ~HASH_MASK; | 377 hash &= ~HASH_MASK; |
363 } | 378 } |
| 379 indirectkey = h->indirect & HASH_INDIRECT_KEY; |
364 for (;;) { | 380 for (;;) { |
365 struct hash_subtable *st = *pst; | 381 struct hash_subtable *st = *pst; |
366 int32 shift = HASH_BITS - (st->power + HASH_USED (flags)); | 382 int32 shift = HASH_BITS - (st->power + HASH_USED (flags)); |
367 int32 index_mask = (1 << st->power) - 1; | 383 int32 index_mask = (1 << st->power) - 1; |
368 int32 i = (hash >> shift) & index_mask; /* i is the natural p
osition of hash */ | 384 int32 i = (hash >> shift) & index_mask; /* i is the natural p
osition of hash */ |
369 struct hash_entry *start_e = | 385 struct hash_entry *start_e = |
370 HASH_OFFSET (st->entry, i * elemsize); /* start_e is
the pointer to element i */ | 386 HASH_OFFSET (st->entry, i * elemsize); /* start_e is
the pointer to element i */ |
371 struct hash_entry *e = start_e; /* e is going to rang
e over [start_e, end_e) */ | 387 struct hash_entry *e = start_e; /* e is going to rang
e over [start_e, end_e) */ |
372 struct hash_entry *end_e; | 388 struct hash_entry *end_e; |
373 hash_hash_t e_hash = e->hash; | 389 hash_hash_t e_hash = e->hash; |
374 | 390 |
375 if ((e_hash & HASH_MASK) == HASH_SUBHASH) { /* a subtable *
/ | 391 if ((e_hash & HASH_MASK) == HASH_SUBHASH) { /* a subtable *
/ |
376 pst = (struct hash_subtable **) e->data; | 392 pst = (struct hash_subtable **) e->data; |
377 flags += HASH_MAKE_USED (st->power); | 393 flags += HASH_MAKE_USED (st->power); |
378 continue; | 394 continue; |
379 } | 395 } |
380 end_e = HASH_OFFSET (start_e, st->limit_bytes); | 396 end_e = HASH_OFFSET (start_e, st->limit_bytes); |
381 while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash <
hash) { | 397 while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash <
hash) { |
382 e = HASH_OFFSET (e, elemsize); | 398 e = HASH_OFFSET (e, elemsize); |
383 i++; | 399 i++; |
384 } | 400 } |
385 if (e != end_e && e_hash != HASH_NIL) { | 401 if (e != end_e && e_hash != HASH_NIL) { |
386 /* ins_e ranges over the elements that may match */ | 402 /* ins_e ranges over the elements that may match */ |
387 struct hash_entry *ins_e = e; | 403 struct hash_entry *ins_e = e; |
388 int32 ins_i = i; | 404 int32 ins_i = i; |
389 hash_hash_t ins_e_hash; | 405 hash_hash_t ins_e_hash; |
390 while (ins_e != end_e && ((e_hash = ins_e->hash) ^ hash)
< HASH_SUBHASH) { | 406 while (ins_e != end_e && ((e_hash = ins_e->hash) ^ hash)
< HASH_SUBHASH) { |
391 » » » » if (HASH_DATA_EQ (eq, t, h, data, ins_e->data))
{ /* a match */ | 407 » » » » void *k = ins_e->data; |
| 408 » » » » if (indirectkey) |
| 409 » » » » » k = *(void**)k; |
| 410 » » » » if (HASH_DATA_EQ (eq, t, h, data, k)) { /* a
match */ |
392 *pres = ins_e->data; | 411 *pres = ins_e->data; |
393 return (1); | 412 return (1); |
394 } | 413 } |
395 assert (e_hash != hash || (flags & HASH_REHASH)
== 0); | 414 assert (e_hash != hash || (flags & HASH_REHASH)
== 0); |
396 hash += (e_hash == hash); /* adjust has
h if it collides */ | 415 hash += (e_hash == hash); /* adjust has
h if it collides */ |
397 ins_e = HASH_OFFSET (ins_e, elemsize); | 416 ins_e = HASH_OFFSET (ins_e, elemsize); |
398 ins_i++; | 417 ins_i++; |
399 if (e_hash <= hash) { /* set e to inser
tion point */ | 418 if (e_hash <= hash) { /* set e to inser
tion point */ |
400 e = ins_e; | 419 e = ins_e; |
401 i = ins_i; | 420 i = ins_i; |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
673 hash_visit (Hmap *h, void (*data_visit) (void *arg, int32 level, void *data), vo
id *arg) | 692 hash_visit (Hmap *h, void (*data_visit) (void *arg, int32 level, void *data), vo
id *arg) |
674 { | 693 { |
675 hash_visit_internal (h->st, 0, 0, data_visit, arg); | 694 hash_visit_internal (h->st, 0, 0, data_visit, arg); |
676 } | 695 } |
677 | 696 |
678 // | 697 // |
679 /// interfaces to go runtime | 698 /// interfaces to go runtime |
680 // | 699 // |
681 | 700 |
682 // hash requires < 256 bytes of data (key+value) stored inline. | 701 // hash requires < 256 bytes of data (key+value) stored inline. |
683 // Only basic types can be key - biggest is complex128 (16 bytes). | 702 // Biggest basic type is complex128 (16 bytes). |
684 // Leave some room to grow, just in case. | 703 // Leave some room to grow, just in case. |
685 enum { | 704 enum { |
686 » MaxValsize = 256 - 64 | 705 » MaxKeysize = 64, |
| 706 » MaxValsize = 256 - MaxKeysize |
687 }; | 707 }; |
688 | 708 |
689 static void** | 709 static void** |
690 hash_indirect(Hmap *h, void *p) | 710 hash_indirect(Hmap *h, void *p) |
691 { | 711 { |
692 » if(h->indirectval) | 712 » if(h->indirect & HASH_INDIRECT_VAL) |
693 p = *(void**)p; | 713 p = *(void**)p; |
694 return p; | 714 return p; |
695 }······· | 715 }······· |
696 | 716 |
697 static int32 debug = 0; | 717 static int32 debug = 0; |
698 | 718 |
699 // makemap(typ *Type, hint uint32) (hmap *map[any]any); | 719 // makemap(typ *Type, hint uint32) (hmap *map[any]any); |
700 Hmap* | 720 Hmap* |
701 runtime·makemap_c(MapType *typ, int64 hint) | 721 runtime·makemap_c(MapType *typ, int64 hint) |
702 { | 722 { |
703 Hmap *h; | 723 Hmap *h; |
| 724 int32 keysize_in_hash; |
704 int32 valsize_in_hash; | 725 int32 valsize_in_hash; |
705 Type *key, *val; | 726 Type *key, *val; |
706 ········ | 727 ········ |
707 key = typ->key; | 728 key = typ->key; |
708 val = typ->elem; | 729 val = typ->elem; |
709 | 730 |
710 if(hint < 0 || (int32)hint != hint) | 731 if(hint < 0 || (int32)hint != hint) |
711 runtime·panicstring("makemap: size out of range"); | 732 runtime·panicstring("makemap: size out of range"); |
712 | 733 |
713 if(key->alg->hash == runtime·nohash) | 734 if(key->alg->hash == runtime·nohash) |
714 runtime·throw("runtime.makemap: unsupported map key type"); | 735 runtime·throw("runtime.makemap: unsupported map key type"); |
715 | 736 |
716 h = runtime·mal(sizeof(*h)); | 737 h = runtime·mal(sizeof(*h)); |
717 | 738 |
718 » valsize_in_hash = val->size; | 739 » if (key->size <= MaxKeysize) |
719 » if (val->size > MaxValsize) { | 740 » » keysize_in_hash = key->size; |
720 » » h->indirectval = 1; | 741 » else { |
| 742 » » h->indirect |= HASH_INDIRECT_KEY; |
| 743 » » keysize_in_hash = sizeof(void*); |
| 744 » } |
| 745 |
| 746 » if (val->size <= MaxValsize) |
| 747 » » valsize_in_hash = val->size; |
| 748 » else { |
| 749 » » h->indirect |= HASH_INDIRECT_VAL; |
721 valsize_in_hash = sizeof(void*); | 750 valsize_in_hash = sizeof(void*); |
722 » } | 751 » } |
723 | 752 |
724 // Align value inside data so that mark-sweep gc can find it. | 753 // Align value inside data so that mark-sweep gc can find it. |
725 » h->valoff = key->size; | 754 » h->valoff = keysize_in_hash; |
726 » assert(h->valoff == key->size); | |
727 if(valsize_in_hash >= sizeof(void*)) | 755 if(valsize_in_hash >= sizeof(void*)) |
728 h->valoff = runtime·rnd(key->size, sizeof(void*)); | 756 h->valoff = runtime·rnd(key->size, sizeof(void*)); |
729 | 757 |
730 hash_init(h, h->valoff+valsize_in_hash, hint); | 758 hash_init(h, h->valoff+valsize_in_hash, hint); |
731 | 759 |
732 // these calculations are compiler dependent. | 760 // these calculations are compiler dependent. |
733 // figure out offsets of map call arguments. | 761 // figure out offsets of map call arguments. |
734 | 762 |
735 if(debug) { | 763 if(debug) { |
736 runtime·printf("makemap: map=%p; keysize=%p; valsize=%p; keyalg=
%p; valalg=%p\n", | 764 runtime·printf("makemap: map=%p; keysize=%p; valsize=%p; keyalg=
%p; valalg=%p\n", |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
873 if(runtime·gcwaiting) | 901 if(runtime·gcwaiting) |
874 runtime·gosched(); | 902 runtime·gosched(); |
875 | 903 |
876 if(av == nil) { | 904 if(av == nil) { |
877 hash_remove(t, h, ak); | 905 hash_remove(t, h, ak); |
878 return; | 906 return; |
879 } | 907 } |
880 | 908 |
881 res = nil; | 909 res = nil; |
882 hit = hash_insert(t, h, ak, (void**)&res); | 910 hit = hash_insert(t, h, ak, (void**)&res); |
883 » if(!hit && h->indirectval) | 911 » if(h->indirect&HASH_INDIRECT_KEY) { |
| 912 » » if(!hit) |
| 913 » » » *(void**)res = runtime·mal(t->key->size); |
| 914 » » t->key->alg->copy(t->key->size, *(void**)res, ak); |
| 915 » } else |
| 916 » » t->key->alg->copy(t->key->size, res, ak); |
| 917 » if(!hit && h->indirect&HASH_INDIRECT_VAL) |
884 *(void**)(res+h->valoff) = runtime·mal(t->elem->size); | 918 *(void**)(res+h->valoff) = runtime·mal(t->elem->size); |
885 t->key->alg->copy(t->key->size, res, ak); | |
886 t->elem->alg->copy(t->elem->size, hash_indirect(h, res+h->valoff), av); | 919 t->elem->alg->copy(t->elem->size, hash_indirect(h, res+h->valoff), av); |
887 | 920 |
888 if(debug) { | 921 if(debug) { |
889 runtime·prints("mapassign: map="); | 922 runtime·prints("mapassign: map="); |
890 runtime·printpointer(h); | 923 runtime·printpointer(h); |
891 runtime·prints("; key="); | 924 runtime·prints("; key="); |
892 t->key->alg->print(t->key->size, ak); | 925 t->key->alg->print(t->key->size, ak); |
893 runtime·prints("; val="); | 926 runtime·prints("; val="); |
894 t->elem->alg->print(t->elem->size, av); | 927 t->elem->alg->print(t->elem->size, av); |
895 runtime·prints("; hit="); | 928 runtime·prints("; hit="); |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1026 Hmap *h; | 1059 Hmap *h; |
1027 byte *ak, *res; | 1060 byte *ak, *res; |
1028 Type *key; | 1061 Type *key; |
1029 | 1062 |
1030 h = it->h; | 1063 h = it->h; |
1031 ak = (byte*)(&it + 1); | 1064 ak = (byte*)(&it + 1); |
1032 | 1065 |
1033 res = it->data; | 1066 res = it->data; |
1034 if(res == nil) | 1067 if(res == nil) |
1035 runtime·throw("runtime.mapiter1: key:val nil pointer"); | 1068 runtime·throw("runtime.mapiter1: key:val nil pointer"); |
| 1069 if(h->indirect&HASH_INDIRECT_KEY) |
| 1070 res = *(void**)res; |
1036 | 1071 |
1037 key = it->t->key; | 1072 key = it->t->key; |
1038 key->alg->copy(key->size, ak, res); | 1073 key->alg->copy(key->size, ak, res); |
1039 | 1074 |
1040 if(debug) { | 1075 if(debug) { |
1041 runtime·prints("mapiter2: iter="); | 1076 runtime·prints("mapiter2: iter="); |
1042 runtime·printpointer(it); | 1077 runtime·printpointer(it); |
1043 runtime·prints("; map="); | 1078 runtime·prints("; map="); |
1044 runtime·printpointer(h); | 1079 runtime·printpointer(h); |
1045 runtime·prints("\n"); | 1080 runtime·prints("\n"); |
1046 } | 1081 } |
1047 } | 1082 } |
1048 | 1083 |
1049 bool | 1084 bool |
1050 runtime·mapiterkey(struct hash_iter *it, void *ak) | 1085 runtime·mapiterkey(struct hash_iter *it, void *ak) |
1051 { | 1086 { |
1052 byte *res; | 1087 byte *res; |
1053 Type *key; | 1088 Type *key; |
1054 | 1089 |
1055 res = it->data; | 1090 res = it->data; |
1056 if(res == nil) | 1091 if(res == nil) |
1057 return false; | 1092 return false; |
| 1093 if(it->h->indirect&HASH_INDIRECT_KEY) |
| 1094 res = *(void**)res; |
1058 key = it->t->key; | 1095 key = it->t->key; |
1059 key->alg->copy(key->size, ak, res); | 1096 key->alg->copy(key->size, ak, res); |
1060 return true; | 1097 return true; |
1061 } | 1098 } |
1062 | 1099 |
1063 // For reflect: | 1100 // For reflect: |
1064 // func mapiterkey(h map) (key iword, ok bool) | 1101 // func mapiterkey(h map) (key iword, ok bool) |
1065 // where an iword is the same word an interface value would use: | 1102 // where an iword is the same word an interface value would use: |
1066 // the actual data if it fits, or else a pointer to the data. | 1103 // the actual data if it fits, or else a pointer to the data. |
1067 void | 1104 void |
1068 reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok) | 1105 reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok) |
1069 { | 1106 { |
1070 byte *res; | 1107 byte *res; |
1071 Type *tkey; | 1108 Type *tkey; |
1072 | 1109 |
1073 key = 0; | 1110 key = 0; |
1074 ok = false; | 1111 ok = false; |
1075 res = it->data; | 1112 res = it->data; |
1076 if(res == nil) { | 1113 if(res == nil) { |
1077 key = 0; | 1114 key = 0; |
1078 ok = false; | 1115 ok = false; |
1079 } else { | 1116 } else { |
| 1117 if(it->h->indirect&HASH_INDIRECT_KEY) |
| 1118 res = *(void**)res; |
1080 tkey = it->t->key; | 1119 tkey = it->t->key; |
1081 key = 0; | 1120 key = 0; |
1082 if(tkey->size <= sizeof(key)) | 1121 if(tkey->size <= sizeof(key)) |
1083 tkey->alg->copy(tkey->size, (byte*)&key, res); | 1122 tkey->alg->copy(tkey->size, (byte*)&key, res); |
1084 else | 1123 else |
1085 key = (uintptr)res; | 1124 key = (uintptr)res; |
1086 ok = true; | 1125 ok = true; |
1087 } | 1126 } |
1088 FLUSH(&key); | 1127 FLUSH(&key); |
1089 FLUSH(&ok); | 1128 FLUSH(&ok); |
(...skipping 23 matching lines...) Expand all Loading... |
1113 | 1152 |
1114 t = it->t; | 1153 t = it->t; |
1115 ak = (byte*)(&it + 1); | 1154 ak = (byte*)(&it + 1); |
1116 av = ak + runtime·rnd(t->key->size, t->elem->align); | 1155 av = ak + runtime·rnd(t->key->size, t->elem->align); |
1117 | 1156 |
1118 res = it->data; | 1157 res = it->data; |
1119 if(res == nil) | 1158 if(res == nil) |
1120 runtime·throw("runtime.mapiter2: key:val nil pointer"); | 1159 runtime·throw("runtime.mapiter2: key:val nil pointer"); |
1121 | 1160 |
1122 h = it->h; | 1161 h = it->h; |
| 1162 if(h->indirect&HASH_INDIRECT_KEY) |
| 1163 res = *(void**)res; |
1123 t->key->alg->copy(t->key->size, ak, res); | 1164 t->key->alg->copy(t->key->size, ak, res); |
1124 t->elem->alg->copy(t->elem->size, av, hash_indirect(h, res+h->valoff)); | 1165 t->elem->alg->copy(t->elem->size, av, hash_indirect(h, res+h->valoff)); |
1125 | 1166 |
1126 if(debug) { | 1167 if(debug) { |
1127 runtime·prints("mapiter2: iter="); | 1168 runtime·prints("mapiter2: iter="); |
1128 runtime·printpointer(it); | 1169 runtime·printpointer(it); |
1129 runtime·prints("; map="); | 1170 runtime·prints("; map="); |
1130 runtime·printpointer(h); | 1171 runtime·printpointer(h); |
1131 runtime·prints("\n"); | 1172 runtime·prints("\n"); |
1132 } | 1173 } |
1133 } | 1174 } |
LEFT | RIGHT |