File: weakcache.hpp

package info (click to toggle)
openmw 0.49.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 33,992 kB
  • sloc: cpp: 372,479; xml: 2,149; sh: 1,403; python: 797; makefile: 26
file content (140 lines) | stat: -rw-r--r-- 3,842 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#ifndef OPENMW_COMPONENTS_WEAKCACHE_HPP
#define OPENMW_COMPONENTS_WEAKCACHE_HPP

#include <memory>
#include <unordered_map>
#include <vector>

namespace Misc
{
    /// \class WeakCache
    /// Provides a container to weakly store pointers to shared data.
    template <typename Key, typename T>
    class WeakCache
    {
    public:
        using WeakPtr = std::weak_ptr<T>;
        using StrongPtr = std::shared_ptr<T>;
        using Map = std::unordered_map<Key, WeakPtr>;

        class iterator
        {
        public:
            iterator(WeakCache* cache, typename Map::iterator current, typename Map::iterator end);
            iterator& operator++();
            bool operator==(const iterator& other) const;
            bool operator!=(const iterator& other) const;
            StrongPtr operator*();

        private:
            WeakCache* mCache;
            typename Map::iterator mCurrent, mEnd;
            StrongPtr mPtr;
        };

        /// Stores a weak pointer to the item.
        void insert(Key key, StrongPtr value, bool prune = true);

        /// Retrieves the item associated with the key.
        /// \return An item or null.
        StrongPtr get(Key key);

        iterator begin();
        iterator end();

        /// Removes known invalid entries
        void prune();

    private:
        Map mData;
        std::vector<Key> mDirty;
    };

    template <typename Key, typename T>
    WeakCache<Key, T>::iterator::iterator(WeakCache* cache, typename Map::iterator current, typename Map::iterator end)
        : mCache(cache)
        , mCurrent(current)
        , mEnd(end)
    {
        // Move to 1st available valid item
        for (; mCurrent != mEnd; ++mCurrent)
        {
            mPtr = mCurrent->second.lock();
            if (mPtr)
                break;
            else
                mCache->mDirty.push_back(mCurrent->first);
        }
    }

    template <typename Key, typename T>
    typename WeakCache<Key, T>::iterator& WeakCache<Key, T>::iterator::operator++()
    {
        auto next = mCurrent;
        ++next;
        return *this = iterator(mCache, next, mEnd);
    }

    template <typename Key, typename T>
    bool WeakCache<Key, T>::iterator::operator==(const iterator& other) const
    {
        return mCurrent == other.mCurrent;
    }

    template <typename Key, typename T>
    bool WeakCache<Key, T>::iterator::operator!=(const iterator& other) const
    {
        return !(*this == other);
    }

    template <typename Key, typename T>
    typename WeakCache<Key, T>::StrongPtr WeakCache<Key, T>::iterator::operator*()
    {
        return mPtr;
    }

    template <typename Key, typename T>
    void WeakCache<Key, T>::insert(Key key, StrongPtr value, bool shouldPrune)
    {
        mData[key] = WeakPtr(value);
        if (shouldPrune)
            prune();
    }

    template <typename Key, typename T>
    typename WeakCache<Key, T>::StrongPtr WeakCache<Key, T>::get(Key key)
    {
        auto searchIt = mData.find(key);
        if (searchIt != mData.end())
            return searchIt->second.lock();
        else
            return StrongPtr();
    }

    template <typename Key, typename T>
    typename WeakCache<Key, T>::iterator WeakCache<Key, T>::begin()
    {
        return iterator(this, mData.begin(), mData.end());
    }

    template <typename Key, typename T>
    typename WeakCache<Key, T>::iterator WeakCache<Key, T>::end()
    {
        return iterator(this, mData.end(), mData.end());
    }

    template <typename Key, typename T>
    void WeakCache<Key, T>::prune()
    {
        // Remove empty entries
        for (auto& key : mDirty)
        {
            auto it = mData.find(key);
            if (it != mData.end() && it->second.use_count() == 0)
                mData.erase(it);
        }
        mDirty.clear();
    }
}

#endif