/src/tesseract/src/ccutil/object_cache.h
Line | Count | Source (jump to first uncovered line) |
1 | | /////////////////////////////////////////////////////////////////////// |
2 | | // File: object_cache.h |
3 | | // Description: A string indexed object cache. |
4 | | // Author: David Eger |
5 | | // |
6 | | // (C) Copyright 2012, Google Inc. |
7 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | // you may not use this file except in compliance with the License. |
9 | | // You may obtain a copy of the License at |
10 | | // http://www.apache.org/licenses/LICENSE-2.0 |
11 | | // Unless required by applicable law or agreed to in writing, software |
12 | | // distributed under the License is distributed on an "AS IS" BASIS, |
13 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | // See the License for the specific language governing permissions and |
15 | | // limitations under the License. |
16 | | // |
17 | | /////////////////////////////////////////////////////////////////////// |
18 | | |
19 | | #ifndef TESSERACT_CCUTIL_OBJECT_CACHE_H_ |
20 | | #define TESSERACT_CCUTIL_OBJECT_CACHE_H_ |
21 | | |
22 | | #include <functional> // for std::function |
23 | | #include <mutex> // for std::mutex |
24 | | #include <string> |
25 | | #include <vector> // for std::vector |
26 | | #include "ccutil.h" |
27 | | #include "errcode.h" |
28 | | |
29 | | namespace tesseract { |
30 | | |
31 | | // A simple object cache which maps a string to an object of type T. |
32 | | // Usually, these are expensive objects that are loaded from disk. |
33 | | // Reference counting is performed, so every Get() needs to be followed later |
34 | | // by a Free(). Actual deletion is accomplished by DeleteUnusedObjects(). |
35 | | template <typename T> |
36 | | class ObjectCache { |
37 | | public: |
38 | 0 | ObjectCache() = default; |
39 | 4 | ~ObjectCache() { |
40 | 4 | std::lock_guard<std::mutex> guard(mu_); |
41 | 36 | for (auto &it : cache_) { |
42 | 36 | if (it.count > 0) { |
43 | 20 | tprintf( |
44 | 20 | "ObjectCache(%p)::~ObjectCache(): WARNING! LEAK! object %p " |
45 | 20 | "still has count %d (id %s)\n", |
46 | 20 | static_cast<void *>(this), static_cast<void *>(it.object), |
47 | 20 | it.count, it.id.c_str()); |
48 | 20 | } else { |
49 | 16 | delete it.object; |
50 | 16 | it.object = nullptr; |
51 | 16 | } |
52 | 36 | } |
53 | 4 | } |
54 | | |
55 | | // Return a pointer to the object identified by id. |
56 | | // If we haven't yet loaded the object, use loader to load it. |
57 | | // If loader fails to load it, record a nullptr entry in the cache |
58 | | // and return nullptr -- further attempts to load will fail (even |
59 | | // with a different loader) until DeleteUnusedObjects() is called. |
60 | | // We delete the given loader. |
61 | 36 | T *Get(const std::string &id, std::function<T *()> loader) { |
62 | 36 | T *retval = nullptr; |
63 | 36 | std::lock_guard<std::mutex> guard(mu_); |
64 | 144 | for (auto &it : cache_) { |
65 | 144 | if (id == it.id) { |
66 | 0 | retval = it.object; |
67 | 0 | if (it.object != nullptr) { |
68 | 0 | it.count++; |
69 | 0 | } |
70 | 0 | return retval; |
71 | 0 | } |
72 | 144 | } |
73 | 36 | cache_.push_back(ReferenceCount()); |
74 | 36 | ReferenceCount &rc = cache_.back(); |
75 | 36 | rc.id = id; |
76 | 36 | retval = rc.object = loader(); |
77 | 36 | rc.count = (retval != nullptr) ? 1 : 0; |
78 | 36 | return retval; |
79 | 36 | } |
80 | | |
81 | | // Decrement the count for t. |
82 | | // Return whether we knew about the given pointer. |
83 | 16 | bool Free(T *t) { |
84 | 16 | if (t == nullptr) { |
85 | 4 | return false; |
86 | 4 | } |
87 | 12 | std::lock_guard<std::mutex> guard(mu_); |
88 | 24 | for (auto &it : cache_) { |
89 | 24 | if (it.object == t) { |
90 | 12 | --it.count; |
91 | 12 | return true; |
92 | 12 | } |
93 | 24 | } |
94 | 0 | return false; |
95 | 12 | } |
96 | | |
97 | 0 | void DeleteUnusedObjects() { |
98 | 0 | std::lock_guard<std::mutex> guard(mu_); |
99 | 0 | cache_.erase(std::remove_if(cache_.begin(), cache_.end(), |
100 | 0 | [](const ReferenceCount &it) { |
101 | 0 | if (it.count <= 0) { |
102 | 0 | delete it.object; |
103 | 0 | return true; |
104 | 0 | } else { |
105 | 0 | return false; |
106 | 0 | } |
107 | 0 | }), |
108 | 0 | cache_.end()); |
109 | 0 | } |
110 | | |
111 | | private: |
112 | | struct ReferenceCount { |
113 | | std::string id; // A unique ID to identify the object (think path on disk) |
114 | | T *object; // A copy of the object in memory. Can be delete'd. |
115 | | int count; // A count of the number of active users of this object. |
116 | | }; |
117 | | |
118 | | std::mutex mu_; |
119 | | std::vector<ReferenceCount> cache_; |
120 | | }; |
121 | | |
122 | | } // namespace tesseract |
123 | | |
124 | | #endif // TESSERACT_CCUTIL_OBJECT_CACHE_H_ |