1 /* go-map-index.c -- find or insert an entry in a map.
3 Copyright 2009 The Go Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file. */
11 #include "go-assert.h"
14 /* Rehash MAP to a larger size. */
17 __go_map_rehash (struct __go_map
*map
)
19 const struct __go_map_descriptor
*descriptor
;
20 const struct __go_type_descriptor
*key_descriptor
;
23 size_t (*hashfn
) (const void *, size_t);
24 uintptr_t old_bucket_count
;
26 uintptr_t new_bucket_count
;
30 descriptor
= map
->__descriptor
;
32 key_descriptor
= descriptor
->__map_descriptor
->__key_type
;
33 key_offset
= descriptor
->__key_offset
;
34 key_size
= key_descriptor
->__size
;
35 hashfn
= key_descriptor
->__hashfn
;
37 old_bucket_count
= map
->__bucket_count
;
38 old_buckets
= map
->__buckets
;
40 new_bucket_count
= __go_map_next_prime (old_bucket_count
* 2);
41 new_buckets
= (void **) __go_alloc (new_bucket_count
* sizeof (void *));
42 __builtin_memset (new_buckets
, 0, new_bucket_count
* sizeof (void *));
44 for (i
= 0; i
< old_bucket_count
; ++i
)
49 for (entry
= old_buckets
[i
]; entry
!= NULL
; entry
= next
)
52 size_t new_bucket_index
;
54 /* We could speed up rehashing at the cost of memory space
55 by caching the hash code. */
56 key_hash
= hashfn (entry
+ key_offset
, key_size
);
57 new_bucket_index
= key_hash
% new_bucket_count
;
59 next
= *(char **) entry
;
60 *(char **) entry
= new_buckets
[new_bucket_index
];
61 new_buckets
[new_bucket_index
] = entry
;
65 __go_free (old_buckets
);
67 map
->__bucket_count
= new_bucket_count
;
68 map
->__buckets
= new_buckets
;
71 /* Find KEY in MAP, return a pointer to the value. If KEY is not
72 present, then if INSERT is false, return NULL, and if INSERT is
73 true, insert a new value and zero-initialize it before returning a
77 __go_map_index (struct __go_map
*map
, const void *key
, _Bool insert
)
79 const struct __go_map_descriptor
*descriptor
;
80 const struct __go_type_descriptor
*key_descriptor
;
82 _Bool (*equalfn
) (const void*, const void*, size_t);
88 descriptor
= map
->__descriptor
;
90 key_descriptor
= descriptor
->__map_descriptor
->__key_type
;
91 key_offset
= descriptor
->__key_offset
;
92 key_size
= key_descriptor
->__size
;
93 __go_assert (key_size
!= 0 && key_size
!= -1UL);
94 equalfn
= key_descriptor
->__equalfn
;
96 key_hash
= key_descriptor
->__hashfn (key
, key_size
);
97 bucket_index
= key_hash
% map
->__bucket_count
;
99 entry
= (char *) map
->__buckets
[bucket_index
];
100 while (entry
!= NULL
)
102 if (equalfn (key
, entry
+ key_offset
, key_size
))
103 return entry
+ descriptor
->__val_offset
;
104 entry
= *(char **) entry
;
110 if (map
->__element_count
>= map
->__bucket_count
)
112 __go_map_rehash (map
);
113 bucket_index
= key_hash
% map
->__bucket_count
;
116 entry
= (char *) __go_alloc (descriptor
->__entry_size
);
117 __builtin_memset (entry
, 0, descriptor
->__entry_size
);
119 __builtin_memcpy (entry
+ key_offset
, key
, key_size
);
121 *(char **) entry
= map
->__buckets
[bucket_index
];
122 map
->__buckets
[bucket_index
] = entry
;
124 map
->__element_count
+= 1;
126 return entry
+ descriptor
->__val_offset
;