SkTDynamicHash.h revision 5d1e5589fe446a59372debd8c7221170e21ec2b8
15d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com/*
25d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com * Copyright 2013 Google Inc.
35d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com *
45d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com * Use of this source code is governed by a BSD-style license that can be
55d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com * found in the LICENSE file.
65d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com */
75d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
85d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com#ifndef SkTDynamicHash_DEFINED
95d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com#define SkTDynamicHash_DEFINED
105d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
115d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com#include "SkTypes.h"
125d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
135d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.comtemplate <typename T, typename KEY, const KEY& (KEY_FROM_T)(const T&),
145d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.comuint32_t (HASH_FROM_KEY)(const Key&), bool (EQ_T_KEY)(const T&, const Key&)>
155d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.comclass SkTDynamicHash {
165d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.comprivate:
175d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    T* fStorage[1];
185d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    T** fArray;
195d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    int fCapacity;
205d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    int fCountUsed;
215d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    int fCountDeleted;
225d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
235d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    unsigned hashMask() const { return fCapacity - 1; }
245d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    const T* deletedValue() const { return reinterpret_cast<const T*>(-1); }
255d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
265d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.compublic:
275d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    SkTDynamicHash() {
285d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        fArray = fStorage;
295d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        fCapacity = 1;
305d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        fCountUsed = fCountDeleted = 0;
315d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    }
325d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    ~SkTDynamicHash() {
335d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        if (fArray != fStorage) {
345d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            sk_free(fArray);
355d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        }
365d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    }
375d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
385d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    T* find(const KEY& key) {
395d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        const T* const deleted = this->deletedValue();
405d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        const unsigned mask = this->hashMask();
415d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        int index = HASH_FROM_KEY(key) & mask;
425d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        const int origIndex = index;
435d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        int delta = 1;
445d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
455d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        do {
465d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            T* candidate = fArray[index];
475d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            if (NULL == candidate) {
485d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                return NULL;
495d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            }
505d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            if (deleted != candidate && EQ_T_KEY(*candidate, key)) {
515d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                return candidate;
525d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            }
535d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            index = (index + delta) & mask;
545d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            delta <<= 1;
555d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        } while (index != origIndex);
565d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        return NULL;
575d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    }
585d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
595d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    bool add(const KEY& key, T* newElement, bool autoGrow = true) {
605d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        const T* const deleted = this->deletedValue();
615d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        for (;;) {
625d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            const unsigned mask = this->hashMask();
635d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            int index = HASH_FROM_KEY(key) & mask;
645d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            const int origIndex = index;
655d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            int delta = 1;
665d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
675d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            do {
685d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                const T* candidate = fArray[index];
695d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                if (NULL == candidate || deleted == candidate) {
705d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                    fArray[index] = newElement;
715d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                    fCountUsed += 1;
725d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                    if (deleted == candidate) {
735d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                        SkASSERT(fCountDeleted > 0);
745d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                        fCountDeleted -= 1;
755d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                    }
765d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                    return true;
775d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                }
785d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                index = (index + delta) & mask;
795d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                delta <<= 1;
805d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            } while (index != origIndex);
815d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            if (autoGrow) {
825d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                this->grow();
835d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            } else {
845d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                return false;
855d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            }
865d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        }
875d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        SkASSERT(!"never get here");
885d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        return false;
895d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    }
905d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
915d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    void remove(const KEY& key) {
925d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        const T* const deleted = this->deletedValue();
935d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        const unsigned mask = this->hashMask();
945d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        const uint32_t hash = HASH_FROM_KEY(key);
955d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        int index = hash & mask;
965d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        SkDEBUGCODE(const int origIndex = index;)
975d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        int delta = 1;
985d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
995d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        for (;;) {
1005d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            const T* candidate = fArray[index];
1015d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            SkASSERT(candidate);
1025d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            if (deleted != candidate && EQ_T_KEY(*candidate, key)) {
1035d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                fArray[index] = const_cast<T*>(deleted);
1045d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                fCountDeleted += 1;
1055d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                break;
1065d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            }
1075d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            index = (index + delta) & mask;
1085d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            delta <<= 1;
1095d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            SkASSERT(index != origIndex);
1105d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        }
1115d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        this->checkStrink();
1125d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    }
1135d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
1145d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.comprivate:
1155d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    void grow() {
1165d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        const T* const deleted = this->deletedValue();
1175d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
1185d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        int oldCapacity = fCapacity;
1195d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        T** oldArray = fArray;
1205d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
1215d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        int newCapacity = oldCapacity << 1;
1225d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        T** newArray = (T**)sk_malloc_throw(sizeof(T*) * newCapacity);
1235d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        sk_bzero(newArray, sizeof(T*) * newCapacity);
1245d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
1255d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        SkDEBUGCODE(int oldCountUsed = fCountUsed;)
1265d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        fArray = newArray;
1275d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        fCapacity = newCapacity;
1285d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        fCountUsed = 0;
1295d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        fCountDeleted = 0;
1305d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
1315d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        for (int i = 0; i < oldCapacity; ++i) {
1325d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            T* elem = oldArray[i];
1335d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            if (NULL == elem || deleted == elem) {
1345d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com                continue;
1355d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            }
1365d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            SkDEBUGCODE(bool success =) this->add(KEY_FROM_T(*elem), elem, false);
1375d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com            SkASSERT(success);
1385d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        }
1395d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        SkASSERT(oldCountUsed == fCountUsed);
1405d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com        sk_free(oldArray);
1415d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    }
1425d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
1435d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com    void checkStrink() {}
1445d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com};
1455d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com
1465d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com#endif
147