mirror of
https://github.com/tesseract-ocr/tesseract.git
synced 2024-12-28 02:58:17 +08:00
126 lines
3.8 KiB
C++
126 lines
3.8 KiB
C++
///////////////////////////////////////////////////////////////////////
|
|
// File: object_cache.h
|
|
// Description: A string indexed object cache.
|
|
// Author: David Eger
|
|
// Created: Fri Jan 27 12:08:00 PST 2012
|
|
//
|
|
// (C) Copyright 2012, Google Inc.
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef TESSERACT_CCUTIL_OBJECT_CACHE_H_
|
|
#define TESSERACT_CCUTIL_OBJECT_CACHE_H_
|
|
|
|
#include "ccutil.h"
|
|
#include "errcode.h"
|
|
#include "genericvector.h"
|
|
#include "tesscallback.h"
|
|
|
|
namespace tesseract {
|
|
|
|
// A simple object cache which maps a string to an object of type T.
|
|
// Usually, these are expensive objects that are loaded from disk.
|
|
// Reference counting is performed, so every Get() needs to be followed later
|
|
// by a Free(). Actual deletion is accomplished by DeleteUnusedObjects().
|
|
template<typename T>
|
|
class ObjectCache {
|
|
public:
|
|
ObjectCache() = default;
|
|
~ObjectCache() {
|
|
mu_.Lock();
|
|
for (int i = 0; i < cache_.size(); i++) {
|
|
if (cache_[i].count > 0) {
|
|
tprintf("ObjectCache(%p)::~ObjectCache(): WARNING! LEAK! object %p "
|
|
"still has count %d (id %s)\n",
|
|
this, cache_[i].object, cache_[i].count,
|
|
cache_[i].id.string());
|
|
} else {
|
|
delete cache_[i].object;
|
|
cache_[i].object = nullptr;
|
|
}
|
|
}
|
|
mu_.Unlock();
|
|
}
|
|
|
|
// Return a pointer to the object identified by id.
|
|
// If we haven't yet loaded the object, use loader to load it.
|
|
// If loader fails to load it, record a nullptr entry in the cache
|
|
// and return nullptr -- further attempts to load will fail (even
|
|
// with a different loader) until DeleteUnusedObjects() is called.
|
|
// We delete the given loader.
|
|
T *Get(STRING id,
|
|
TessResultCallback<T *> *loader) {
|
|
T *retval = nullptr;
|
|
mu_.Lock();
|
|
for (int i = 0; i < cache_.size(); i++) {
|
|
if (id == cache_[i].id) {
|
|
retval = cache_[i].object;
|
|
if (cache_[i].object != nullptr) {
|
|
cache_[i].count++;
|
|
}
|
|
mu_.Unlock();
|
|
delete loader;
|
|
return retval;
|
|
}
|
|
}
|
|
cache_.push_back(ReferenceCount());
|
|
ReferenceCount &rc = cache_.back();
|
|
rc.id = id;
|
|
retval = rc.object = loader->Run();
|
|
rc.count = (retval != nullptr) ? 1 : 0;
|
|
mu_.Unlock();
|
|
return retval;
|
|
}
|
|
|
|
// Decrement the count for t.
|
|
// Return whether we knew about the given pointer.
|
|
bool Free(T *t) {
|
|
if (t == nullptr) return false;
|
|
mu_.Lock();
|
|
for (int i = 0; i < cache_.size(); i++) {
|
|
if (cache_[i].object == t) {
|
|
--cache_[i].count;
|
|
mu_.Unlock();
|
|
return true;
|
|
}
|
|
}
|
|
mu_.Unlock();
|
|
return false;
|
|
}
|
|
|
|
void DeleteUnusedObjects() {
|
|
mu_.Lock();
|
|
for (int i = cache_.size() - 1; i >= 0; i--) {
|
|
if (cache_[i].count <= 0) {
|
|
delete cache_[i].object;
|
|
cache_.remove(i);
|
|
}
|
|
}
|
|
mu_.Unlock();
|
|
}
|
|
|
|
private:
|
|
struct ReferenceCount {
|
|
STRING id; // A unique ID to identify the object (think path on disk)
|
|
T *object; // A copy of the object in memory. Can be delete'd.
|
|
int count; // A count of the number of active users of this object.
|
|
};
|
|
|
|
CCUtilMutex mu_;
|
|
GenericVector<ReferenceCount> cache_;
|
|
};
|
|
|
|
} // namespace tesseract
|
|
|
|
|
|
#endif // TESSERACT_CCUTIL_OBJECT_CACHE_H_
|