diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libgo/runtime/go-map-index.c | |
download | cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.bz2 cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libgo/runtime/go-map-index.c')
-rw-r--r-- | libgo/runtime/go-map-index.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/libgo/runtime/go-map-index.c b/libgo/runtime/go-map-index.c new file mode 100644 index 000000000..1561c97a6 --- /dev/null +++ b/libgo/runtime/go-map-index.c @@ -0,0 +1,127 @@ +/* go-map-index.c -- find or insert an entry in a map. + + Copyright 2009 The Go Authors. All rights reserved. + Use of this source code is governed by a BSD-style + license that can be found in the LICENSE file. */ + +#include <stddef.h> +#include <stdlib.h> + +#include "go-alloc.h" +#include "go-assert.h" +#include "map.h" + +/* Rehash MAP to a larger size. */ + +static void +__go_map_rehash (struct __go_map *map) +{ + const struct __go_map_descriptor *descriptor; + const struct __go_type_descriptor *key_descriptor; + size_t key_offset; + size_t key_size; + size_t (*hashfn) (const void *, size_t); + size_t old_bucket_count; + void **old_buckets; + size_t new_bucket_count; + void **new_buckets; + size_t i; + + descriptor = map->__descriptor; + + key_descriptor = descriptor->__map_descriptor->__key_type; + key_offset = descriptor->__key_offset; + key_size = key_descriptor->__size; + hashfn = key_descriptor->__hashfn; + + old_bucket_count = map->__bucket_count; + old_buckets = map->__buckets; + + new_bucket_count = __go_map_next_prime (old_bucket_count * 2); + new_buckets = (void **) __go_alloc (new_bucket_count * sizeof (void *)); + __builtin_memset (new_buckets, 0, new_bucket_count * sizeof (void *)); + + for (i = 0; i < old_bucket_count; ++i) + { + char* entry; + char* next; + + for (entry = old_buckets[i]; entry != NULL; entry = next) + { + size_t key_hash; + size_t new_bucket_index; + + /* We could speed up rehashing at the cost of memory space + by caching the hash code. */ + key_hash = hashfn (entry + key_offset, key_size); + new_bucket_index = key_hash % new_bucket_count; + + next = *(char **) entry; + *(char **) entry = new_buckets[new_bucket_index]; + new_buckets[new_bucket_index] = entry; + } + } + + __go_free (old_buckets); + + map->__bucket_count = new_bucket_count; + map->__buckets = new_buckets; +} + +/* Find KEY in MAP, return a pointer to the value. If KEY is not + present, then if INSERT is false, return NULL, and if INSERT is + true, insert a new value and zero-initialize it before returning a + pointer to it. */ + +void * +__go_map_index (struct __go_map *map, const void *key, _Bool insert) +{ + const struct __go_map_descriptor *descriptor; + const struct __go_type_descriptor *key_descriptor; + size_t key_offset; + _Bool (*equalfn) (const void*, const void*, size_t); + size_t key_hash; + size_t key_size; + size_t bucket_index; + char *entry; + + descriptor = map->__descriptor; + + key_descriptor = descriptor->__map_descriptor->__key_type; + key_offset = descriptor->__key_offset; + key_size = key_descriptor->__size; + __go_assert (key_size != 0 && key_size != -1UL); + equalfn = key_descriptor->__equalfn; + + key_hash = key_descriptor->__hashfn (key, key_size); + bucket_index = key_hash % map->__bucket_count; + + entry = (char *) map->__buckets[bucket_index]; + while (entry != NULL) + { + if (equalfn (key, entry + key_offset, key_size)) + return entry + descriptor->__val_offset; + entry = *(char **) entry; + } + + if (!insert) + return NULL; + + if (map->__element_count >= map->__bucket_count) + { + __go_map_rehash (map); + bucket_index = key_hash % map->__bucket_count; + } + + entry = (char *) __go_alloc (descriptor->__entry_size); + __builtin_memset (entry, 0, descriptor->__entry_size); + + __builtin_memcpy (entry + key_offset, key, key_size); + + *(char **) entry = map->__buckets[bucket_index]; + map->__buckets[bucket_index] = entry; + + map->__element_count += 1; + + return entry + descriptor->__val_offset; +} |