OSDN Git Service

Use backend interface for map descriptors.
[pf3gnuchains/gcc-fork.git] / libgo / runtime / go-map-index.c
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 "go-alloc.h"
11 #include "go-assert.h"
12 #include "map.h"
13
14 /* Rehash MAP to a larger size.  */
15
16 static void
17 __go_map_rehash (struct __go_map *map)
18 {
19   const struct __go_map_descriptor *descriptor;
20   const struct __go_type_descriptor *key_descriptor;
21   uintptr_t key_offset;
22   size_t key_size;
23   size_t (*hashfn) (const void *, size_t);
24   uintptr_t old_bucket_count;
25   void **old_buckets;
26   uintptr_t new_bucket_count;
27   void **new_buckets;
28   uintptr_t i;
29
30   descriptor = map->__descriptor;
31
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;
36
37   old_bucket_count = map->__bucket_count;
38   old_buckets = map->__buckets;
39
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 *));
43
44   for (i = 0; i < old_bucket_count; ++i)
45     {
46       char* entry;
47       char* next;
48
49       for (entry = old_buckets[i]; entry != NULL; entry = next)
50         {
51           size_t key_hash;
52           size_t new_bucket_index;
53
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;
58
59           next = *(char **) entry;
60           *(char **) entry = new_buckets[new_bucket_index];
61           new_buckets[new_bucket_index] = entry;
62         }
63     }
64
65   __go_free (old_buckets);
66
67   map->__bucket_count = new_bucket_count;
68   map->__buckets = new_buckets;
69 }
70
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
74    pointer to it.  */
75
76 void *
77 __go_map_index (struct __go_map *map, const void *key, _Bool insert)
78 {
79   const struct __go_map_descriptor *descriptor;
80   const struct __go_type_descriptor *key_descriptor;
81   uintptr_t key_offset;
82   _Bool (*equalfn) (const void*, const void*, size_t);
83   size_t key_hash;
84   size_t key_size;
85   size_t bucket_index;
86   char *entry;
87
88   descriptor = map->__descriptor;
89
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;
95
96   key_hash = key_descriptor->__hashfn (key, key_size);
97   bucket_index = key_hash % map->__bucket_count;
98
99   entry = (char *) map->__buckets[bucket_index];
100   while (entry != NULL)
101     {
102       if (equalfn (key, entry + key_offset, key_size))
103         return entry + descriptor->__val_offset;
104       entry = *(char **) entry;
105     }
106
107   if (!insert)
108     return NULL;
109
110   if (map->__element_count >= map->__bucket_count)
111     {
112       __go_map_rehash (map);
113       bucket_index = key_hash % map->__bucket_count;
114     }
115
116   entry = (char *) __go_alloc (descriptor->__entry_size);
117   __builtin_memset (entry, 0, descriptor->__entry_size);
118
119   __builtin_memcpy (entry + key_offset, key, key_size);
120
121   *(char **) entry = map->__buckets[bucket_index];
122   map->__buckets[bucket_index] = entry;
123
124   map->__element_count += 1;
125
126   return entry + descriptor->__val_offset;
127 }