Coverage Report

Created: 2025-06-13 07:15

/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_