github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/go-map-index.c (about) 1 /* go-map-index.c -- find or insert an entry in a map. 2 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. */ 6 7 #include <stddef.h> 8 #include <stdlib.h> 9 10 #include "runtime.h" 11 #include "malloc.h" 12 #include "go-alloc.h" 13 #include "go-assert.h" 14 #include "map.h" 15 16 /* Rehash MAP to a larger size. */ 17 18 static void 19 __go_map_rehash (struct __go_map *map) 20 { 21 const struct __go_map_descriptor *descriptor; 22 const struct __go_type_descriptor *key_descriptor; 23 uintptr_t key_offset; 24 size_t key_size; 25 const FuncVal *hashfn; 26 uintptr_t old_bucket_count; 27 void **old_buckets; 28 uintptr_t new_bucket_count; 29 void **new_buckets; 30 uintptr_t i; 31 32 descriptor = map->__descriptor; 33 34 key_descriptor = descriptor->__map_descriptor->__key_type; 35 key_offset = descriptor->__key_offset; 36 key_size = key_descriptor->__size; 37 hashfn = key_descriptor->__hashfn; 38 39 old_bucket_count = map->__bucket_count; 40 old_buckets = map->__buckets; 41 42 new_bucket_count = __go_map_next_prime (old_bucket_count * 2); 43 new_buckets = (void **) __go_alloc (new_bucket_count * sizeof (void *)); 44 __builtin_memset (new_buckets, 0, new_bucket_count * sizeof (void *)); 45 46 for (i = 0; i < old_bucket_count; ++i) 47 { 48 char* entry; 49 char* next; 50 51 for (entry = old_buckets[i]; entry != NULL; entry = next) 52 { 53 size_t key_hash; 54 size_t new_bucket_index; 55 56 /* We could speed up rehashing at the cost of memory space 57 by caching the hash code. */ 58 key_hash = __go_call_hashfn (hashfn, entry + key_offset, key_size); 59 new_bucket_index = key_hash % new_bucket_count; 60 61 next = *(char **) entry; 62 *(char **) entry = new_buckets[new_bucket_index]; 63 new_buckets[new_bucket_index] = entry; 64 } 65 } 66 67 if (old_bucket_count * sizeof (void *) >= TinySize) 68 __go_free (old_buckets); 69 70 map->__bucket_count = new_bucket_count; 71 map->__buckets = new_buckets; 72 } 73 74 /* Find KEY in MAP, return a pointer to the value. If KEY is not 75 present, then if INSERT is false, return NULL, and if INSERT is 76 true, insert a new value and zero-initialize it before returning a 77 pointer to it. */ 78 79 void * 80 __go_map_index (struct __go_map *map, const void *key, _Bool insert) 81 { 82 const struct __go_map_descriptor *descriptor; 83 const struct __go_type_descriptor *key_descriptor; 84 uintptr_t key_offset; 85 const FuncVal *equalfn; 86 size_t key_hash; 87 size_t key_size; 88 size_t bucket_index; 89 char *entry; 90 91 if (map == NULL) 92 { 93 if (insert) 94 runtime_panicstring ("assignment to entry in nil map"); 95 return NULL; 96 } 97 98 descriptor = map->__descriptor; 99 100 key_descriptor = descriptor->__map_descriptor->__key_type; 101 key_offset = descriptor->__key_offset; 102 key_size = key_descriptor->__size; 103 __go_assert (key_size != -1UL); 104 equalfn = key_descriptor->__equalfn; 105 106 key_hash = __go_call_hashfn (key_descriptor->__hashfn, key, key_size); 107 bucket_index = key_hash % map->__bucket_count; 108 109 entry = (char *) map->__buckets[bucket_index]; 110 while (entry != NULL) 111 { 112 if (__go_call_equalfn (equalfn, key, entry + key_offset, key_size)) 113 return entry + descriptor->__val_offset; 114 entry = *(char **) entry; 115 } 116 117 if (!insert) 118 return NULL; 119 120 if (map->__element_count >= map->__bucket_count) 121 { 122 __go_map_rehash (map); 123 bucket_index = key_hash % map->__bucket_count; 124 } 125 126 entry = (char *) __go_alloc (descriptor->__entry_size); 127 __builtin_memset (entry, 0, descriptor->__entry_size); 128 129 __builtin_memcpy (entry + key_offset, key, key_size); 130 131 *(char **) entry = map->__buckets[bucket_index]; 132 map->__buckets[bucket_index] = entry; 133 134 map->__element_count += 1; 135 136 return entry + descriptor->__val_offset; 137 }