1 // Copyright (C) 2014 The Android Open Source Project
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #include "emugl/common/id_to_object_map.h"
23 typedef IdToObjectMapBase::KeyType KeyType;
28 kMinCapacity = (1 << kMinShift),
30 kMinLoad = kLoadScale/4, // 25% minimum load.
31 kMaxLoad = kLoadScale*3/4, // 75% maximum load.
33 kInvalidKey = IdToObjectMapBase::kMaxId + 1U,
34 kTombstone = IdToObjectMapBase::kMaxId + 2U,
37 // Return a number that indicates if the current |capacity| is appropriate
38 // to hold |size| items in our map.
39 // -1 -> the capacity is too small and needs to be increased.
40 // 0 -> the capacity is ok.
41 // +1 -> the capacity is too large and needs to be decreased.
42 int capacityCompare(size_t shift, size_t size) {
43 size_t capacity = 1U << shift;
44 // Essentially, one can rewrite:
47 // size / capacity < minLoad
48 // capacity * minLoad > size
49 if (capacity * kMinLoad > size * kLoadScale)
52 // Similarly, one can rewrite:
55 // size / capacity > maxLoad
56 // capacity * maxLoad < size
57 if (capacity * kMaxLoad < size * kLoadScale)
63 size_t probeKeys(const KeyType* keys, size_t shift, KeyType key) {
64 static const int kPrimes[] = {
81 65521, /* For 1 << 16 */
96 2147483647 /* For 1 << 31 */
99 size_t slot = key % kPrimes[shift];
102 KeyType k = keys[slot];
103 if (k == kInvalidKey || k == kTombstone || k == key)
107 slot = (slot + step) & (1U << shift);
113 IdToObjectMapBase::IdToObjectMapBase() :
114 mCount(0), mShift(kMinShift) {
115 size_t capacity = 1U << mShift;
116 mKeys = static_cast<KeyType*>(::calloc(sizeof(mKeys[0]), capacity));
117 mValues = static_cast<void**>(::calloc(sizeof(mValues[0]), capacity));
118 for (size_t n = 0; n < capacity; ++n) {
119 mKeys[n] = kInvalidKey;
123 IdToObjectMapBase::~IdToObjectMapBase() {
130 bool IdToObjectMapBase::contains(KeyType key) const {
131 size_t slot = probeKeys(mKeys, mShift, key);
132 switch (mKeys[slot]) {
142 bool IdToObjectMapBase::find(KeyType key, void** value) const {
143 size_t slot = probeKeys(mKeys, mShift, key);
144 if (!isValidKey(mKeys[slot])) {
148 *value = mValues[slot];
152 void* IdToObjectMapBase::set(KeyType key, void* value) {
156 size_t slot = probeKeys(mKeys, mShift, key);
158 if (isValidKey(mKeys[slot])) {
159 result = mValues[slot];
160 mValues[slot] = value;
163 mValues[slot] = value;
171 void* IdToObjectMapBase::remove(KeyType key) {
172 size_t slot = probeKeys(mKeys, mShift, key);
173 if (!isValidKey(mKeys[slot]))
176 void* result = mValues[slot];
177 mValues[slot] = NULL;
178 mKeys[slot] = kTombstone;
183 void IdToObjectMapBase::resize(size_t newSize) {
184 int ret = capacityCompare(mShift, newSize);
188 size_t oldCapacity = 1U << mShift;
189 size_t newShift = mShift;
192 // Capacity is too small and must be increased.
194 if (newShift == kMaxShift)
197 } while (capacityCompare(newShift, newSize) < 0);
199 // Capacity is too large and must be decreased.
201 if (newShift == kMinShift)
204 } while (capacityCompare(newShift, newSize) > 0);
206 if (newShift == mShift)
209 // Allocate new arrays.
210 size_t newCapacity = 1U << newShift;
211 KeyType* newKeys = static_cast<KeyType*>(
212 ::calloc(sizeof(newKeys[0]), newCapacity));
213 void** newValues = static_cast<void**>(
214 ::calloc(sizeof(newValues[0]), newCapacity));
215 for (size_t n = 0; n < newCapacity; ++n)
216 newKeys[n] = kInvalidKey;
218 // Copy old entries into new arrays.
219 for (size_t n = 0; n < oldCapacity; ++n) {
220 KeyType key = mKeys[n];
221 if (isValidKey(key)) {
222 size_t newSlot = probeKeys(newKeys, newShift, key);
223 newKeys[newSlot] = key;
224 newValues[newSlot] = mValues[n];
228 // Swap arrays, and get rid of old ones.