OSDN Git Service

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