tesseract
3.03
|
00001 00002 // File: object_cache.h 00003 // Description: A string indexed object cache. 00004 // Author: David Eger 00005 // Created: Fri Jan 27 12:08:00 PST 2012 00006 // 00007 // (C) Copyright 2012, Google Inc. 00008 // Licensed under the Apache License, Version 2.0 (the "License"); 00009 // you may not use this file except in compliance with the License. 00010 // You may obtain a copy of the License at 00011 // http://www.apache.org/licenses/LICENSE-2.0 00012 // Unless required by applicable law or agreed to in writing, software 00013 // distributed under the License is distributed on an "AS IS" BASIS, 00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 // See the License for the specific language governing permissions and 00016 // limitations under the License. 00017 // 00019 00020 #ifndef TESSERACT_CCUTIL_OBJECT_CACHE_H_ 00021 #define TESSERACT_CCUTIL_OBJECT_CACHE_H_ 00022 00023 #include "ccutil.h" 00024 #include "errcode.h" 00025 #include "genericvector.h" 00026 #include "tesscallback.h" 00027 00028 namespace tesseract { 00029 00030 // A simple object cache which maps a string to an object of type T. 00031 // Usually, these are expensive objects that are loaded from disk. 00032 // Reference counting is performed, so every Get() needs to be followed later 00033 // by a Free(). Actual deletion is accomplished by DeleteUnusedObjects(). 00034 template<typename T> 00035 class ObjectCache { 00036 public: 00037 ObjectCache() {} 00038 ~ObjectCache() { 00039 mu_.Lock(); 00040 for (int i = 0; i < cache_.size(); i++) { 00041 if (cache_[i].count > 0) { 00042 tprintf("ObjectCache(%p)::~ObjectCache(): WARNING! LEAK! object %p " 00043 "still has count %d (id %s)\n", 00044 this, cache_[i].object, cache_[i].count, 00045 cache_[i].id.string()); 00046 } else { 00047 delete cache_[i].object; 00048 cache_[i].object = NULL; 00049 } 00050 } 00051 mu_.Unlock(); 00052 } 00053 00054 // Return a pointer to the object identified by id. 00055 // If we haven't yet loaded the object, use loader to load it. 00056 // If loader fails to load it, record a NULL entry in the cache 00057 // and return NULL -- further attempts to load will fail (even 00058 // with a different loader) until DeleteUnusedObjects() is called. 00059 // We delete the given loader. 00060 T *Get(STRING id, 00061 TessResultCallback<T *> *loader) { 00062 T *retval = NULL; 00063 mu_.Lock(); 00064 for (int i = 0; i < cache_.size(); i++) { 00065 if (id == cache_[i].id) { 00066 retval = cache_[i].object; 00067 if (cache_[i].object != NULL) { 00068 cache_[i].count++; 00069 } 00070 mu_.Unlock(); 00071 delete loader; 00072 return retval; 00073 } 00074 } 00075 cache_.push_back(ReferenceCount()); 00076 ReferenceCount &rc = cache_.back(); 00077 rc.id = id; 00078 retval = rc.object = loader->Run(); 00079 rc.count = (retval != NULL) ? 1 : 0; 00080 mu_.Unlock(); 00081 return retval; 00082 } 00083 00084 // Decrement the count for t. 00085 // Return whether we knew about the given pointer. 00086 bool Free(T *t) { 00087 if (t == NULL) return false; 00088 mu_.Lock(); 00089 for (int i = 0; i < cache_.size(); i++) { 00090 if (cache_[i].object == t) { 00091 --cache_[i].count; 00092 mu_.Unlock(); 00093 return true; 00094 } 00095 } 00096 mu_.Unlock(); 00097 return false; 00098 } 00099 00100 void DeleteUnusedObjects() { 00101 mu_.Lock(); 00102 for (int i = cache_.size() - 1; i >= 0; i--) { 00103 if (cache_[i].count <= 0) { 00104 delete cache_[i].object; 00105 cache_.remove(i); 00106 } 00107 } 00108 mu_.Unlock(); 00109 } 00110 00111 private: 00112 struct ReferenceCount { 00113 STRING id; // A unique ID to identify the object (think path on disk) 00114 T *object; // A copy of the object in memory. Can be delete'd. 00115 int count; // A count of the number of active users of this object. 00116 }; 00117 00118 CCUtilMutex mu_; 00119 GenericVector<ReferenceCount> cache_; 00120 }; 00121 00122 } // namespace tesseract 00123 00124 00125 #endif // TESSERACT_CCUTIL_OBJECT_CACHE_H_