18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
68a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef SkTDict_DEFINED
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkTDict_DEFINED
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkChunkAlloc.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTSearch.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTDArray.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtemplate <typename T> class SkTDict : SkNoncopyable {
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkTDict(size_t minStringAlloc) : fStrings(minStringAlloc) {}
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19859b92448b27bb16852474f9a612748b3fd816d5reed    void reset() {
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fArray.reset();
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fStrings.reset();
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count() const { return fArray.count(); }
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
26859b92448b27bb16852474f9a612748b3fd816d5reed    bool set(const char name[], const T& value) {
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return set(name, strlen(name), value);
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
30859b92448b27bb16852474f9a612748b3fd816d5reed    bool set(const char name[], size_t len, const T& value) {
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(name);
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int index = this->find_index(name, len);
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
35859b92448b27bb16852474f9a612748b3fd816d5reed        if (index >= 0) {
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fArray[index].fValue = value;
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
38859b92448b27bb16852474f9a612748b3fd816d5reed        } else {
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            Pair*   pair = fArray.insert(~index);
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            char*   copy = (char*)fStrings.alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType);
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            memcpy(copy, name, len);
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            copy[len] = '\0';
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            pair->fName = copy;
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            pair->fValue = value;
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return true;
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
49859b92448b27bb16852474f9a612748b3fd816d5reed    bool find(const char name[]) const {
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->find_index(name) >= 0;
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
53859b92448b27bb16852474f9a612748b3fd816d5reed    bool find(const char name[], size_t len) const {
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->find_index(name, len) >= 0;
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
57859b92448b27bb16852474f9a612748b3fd816d5reed    bool find(const char name[], T* value) const {
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return find(name, strlen(name), value);
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
61859b92448b27bb16852474f9a612748b3fd816d5reed    bool find(const char name[], size_t len, T* value) const {
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int index = this->find_index(name, len);
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
64859b92448b27bb16852474f9a612748b3fd816d5reed        if (index >= 0) {
65859b92448b27bb16852474f9a612748b3fd816d5reed            if (value) {
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                *value = fArray[index].fValue;
67859b92448b27bb16852474f9a612748b3fd816d5reed            }
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return true;
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
73859b92448b27bb16852474f9a612748b3fd816d5reed    bool findKey(T& value, const char** name) const {
74aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org        const Pair* end = fArray.end();
75aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org        for (const Pair* pair = fArray.begin(); pair < end; pair++) {
76859b92448b27bb16852474f9a612748b3fd816d5reed            if (pair->fValue != value) {
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                continue;
78859b92448b27bb16852474f9a612748b3fd816d5reed            }
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *name = pair->fName;
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return true;
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    struct Pair {
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const char* fName;
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        T           fValue;
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
90859b92448b27bb16852474f9a612748b3fd816d5reed        friend int operator<(const Pair& a, const Pair& b) {
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return strcmp(a.fName, b.fName);
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
93859b92448b27bb16852474f9a612748b3fd816d5reed
94859b92448b27bb16852474f9a612748b3fd816d5reed        friend int operator!=(const Pair& a, const Pair& b) {
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return strcmp(a.fName, b.fName);
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    friend class Iter;
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    class Iter {
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    public:
103859b92448b27bb16852474f9a612748b3fd816d5reed        Iter(const SkTDict<T>& dict) {
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fIter = dict.fArray.begin();
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fStop = dict.fArray.end();
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
107859b92448b27bb16852474f9a612748b3fd816d5reed
108859b92448b27bb16852474f9a612748b3fd816d5reed        const char* next(T* value) {
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            const char* name = NULL;
110859b92448b27bb16852474f9a612748b3fd816d5reed            if (fIter < fStop) {
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                name = fIter->fName;
112859b92448b27bb16852474f9a612748b3fd816d5reed                if (value) {
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    *value = fIter->fValue;
114859b92448b27bb16852474f9a612748b3fd816d5reed                }
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fIter += 1;
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return name;
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    private:
120aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org        const Pair*   fIter;
121aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org        const Pair*   fStop;
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkTDArray<Pair> fArray;
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkChunkAlloc    fStrings;
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
128859b92448b27bb16852474f9a612748b3fd816d5reed    int find_index(const char name[]) const {
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return find_index(name, strlen(name));
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
132859b92448b27bb16852474f9a612748b3fd816d5reed    int find_index(const char name[], size_t len) const {
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(name);
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int count = fArray.count();
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int index = ~0;
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
138859b92448b27bb16852474f9a612748b3fd816d5reed        if (count) {
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            index = SkStrSearch(&fArray.begin()->fName, count, name, len, sizeof(Pair));
140859b92448b27bb16852474f9a612748b3fd816d5reed        }
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return index;
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    friend class Iter;
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
147