tesseract  5.0.0
object_cache.h
Go to the documentation of this file.
1 // 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 //
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  ObjectCache() = default;
40  std::lock_guard<std::mutex> guard(mu_);
41  for (auto &it : cache_) {
42  if (it.count > 0) {
43  tprintf(
44  "ObjectCache(%p)::~ObjectCache(): WARNING! LEAK! object %p "
45  "still has count %d (id %s)\n",
46  this, it.object, it.count, it.id.c_str());
47  } else {
48  delete it.object;
49  it.object = nullptr;
50  }
51  }
52  }
53 
54  // Return a pointer to the object identified by id.
55  // If we haven't yet loaded the object, use loader to load it.
56  // If loader fails to load it, record a nullptr entry in the cache
57  // and return nullptr -- further attempts to load will fail (even
58  // with a different loader) until DeleteUnusedObjects() is called.
59  // We delete the given loader.
60  T *Get(const std::string &id, std::function<T *()> loader) {
61  T *retval = nullptr;
62  std::lock_guard<std::mutex> guard(mu_);
63  for (auto &it : cache_) {
64  if (id == it.id) {
65  retval = it.object;
66  if (it.object != nullptr) {
67  it.count++;
68  }
69  return retval;
70  }
71  }
72  cache_.push_back(ReferenceCount());
73  ReferenceCount &rc = cache_.back();
74  rc.id = id;
75  retval = rc.object = loader();
76  rc.count = (retval != nullptr) ? 1 : 0;
77  return retval;
78  }
79 
80  // Decrement the count for t.
81  // Return whether we knew about the given pointer.
82  bool Free(T *t) {
83  if (t == nullptr) {
84  return false;
85  }
86  std::lock_guard<std::mutex> guard(mu_);
87  for (auto &it : cache_) {
88  if (it.object == t) {
89  --it.count;
90  return true;
91  }
92  }
93  return false;
94  }
95 
97  std::lock_guard<std::mutex> guard(mu_);
98  for (auto it = cache_.rbegin(); it != cache_.rend(); ++it) {
99  if (it->count <= 0) {
100  delete it->object;
101  cache_.erase(std::next(it).base());
102  }
103  }
104  }
105 
106 private:
107  struct ReferenceCount {
108  std::string id; // A unique ID to identify the object (think path on disk)
109  T *object; // A copy of the object in memory. Can be delete'd.
110  int count; // A count of the number of active users of this object.
111  };
112 
113  std::mutex mu_;
114  std::vector<ReferenceCount> cache_;
115 };
116 
117 } // namespace tesseract
118 
119 #endif // TESSERACT_CCUTIL_OBJECT_CACHE_H_
void tprintf(const char *format,...)
Definition: tprintf.cpp:41
T * Get(const std::string &id, std::function< T *()> loader)
Definition: object_cache.h:60