Skip to content

Instantly share code, notes, and snippets.

@reyoung
Created December 23, 2015 06:43
Show Gist options
  • Save reyoung/87f230ebc0dfc242ad90 to your computer and use it in GitHub Desktop.
Save reyoung/87f230ebc0dfc242ad90 to your computer and use it in GitHub Desktop.
A C++ 11 key-value object instance cache.
#include <memory>
#include <unordered_map>
#include <functional>
#include <mutex>
#include <glog/logging.h>
/**
* Key-Value Cache Helper.
*
* It store a object instance global. User can invoke get method by key and a
* object creator callback. If there is a instance stored in cache, then it will
* return a shared_ptr of it, otherwise, it will invoke creator callback, create
* a new instance store global, and return it.
*
* There are two kind of KVCache, WeakKVCache and StrongKVCache.
* In WeakKVCache, the cache instance will release when nobody hold a reference
* to it.
* In StrongKVCache, the cache instance will never release.
*
* Use WeakKVCache::Type or StrongKVCache::Type to get these types. (Because
* template alias is not implemented in gcc46..)
*
* The KType is the key type.
* The VType is the value type.
* The PtrType is either std::shared_ptr<VType> or std::weak_ptr<VType>. Maybe
* ThreadLocalPtr in future.
* The Hash is the key hasher object.
*/
template <typename KType, typename VType, typename PtrType,
typename Hash=std::hash<KType>>
class KVCache {
public:
// Interfaces
KVCache();
/**
* Get Cache Instance.
*
* @param key: The cache key.
* @param creator: The value creator, it will be invoked when there is no
* instance store in cache.
*/
std::shared_ptr<VType> get(const KType& key,
const std::function<VType*()>& creator);
};
/**
* WeakKVCache implementation.
* @see KVCache document.
*/
template <typename KType, typename VType, typename Hash>
class KVCache<KType, VType, std::weak_ptr<VType>, Hash> {
public:
KVCache() {}
std::shared_ptr<VType> get(const KType& key,
const std::function<VType*()>& creator) {
std::lock_guard<std::mutex> guard(this->lock_);
auto it = this->storage_.find(key);
if (it != this->storage_.end()) {
auto & val = it->second;
auto retVal = val.lock();
if (retVal != nullptr) {
return retVal;
} // else fall trough. Because it is WeakPtr Cache.
}
auto rawPtr = creator();
CHECK(rawPtr != nullptr);
std::shared_ptr<VType> retVal(rawPtr);
this->storage_[key] = retVal;
return retVal;
}
private:
std::mutex lock_;
std::unordered_map<KType, std::weak_ptr<VType>, Hash> storage_;
};
/**
* StrongKVCache implementation.
* @see KVCache document.
*/
template <typename KType, typename VType, typename Hash>
class KVCache<KType, VType, std::shared_ptr<VType>, Hash> {
public:
KVCache() {}
std::shared_ptr<VType> get(const KType& key,
const std::function<VType*()>& creator) {
std::lock_guard<std::mutex> guard(this->lock_);
auto it = this->storage_.find(key);
if (it != this->storage_.end()) {
auto & val = it->second;
return val;
} else {
auto rawPtr = creator();
CHECK(rawPtr != nullptr);
std::shared_ptr<VType> retVal(rawPtr);
this->storage_[key] = retVal;
return retVal;
}
}
private:
std::mutex lock_;
std::unordered_map<KType, std::shared_ptr<VType>, Hash> storage_;
};
template <typename KType, typename VType, typename Hash=std::hash<KType>>
class WeakKVCache { // Template alias is supported begin gcc 4.7.
public:
typedef KVCache<KType, VType, std::weak_ptr<VType>, Hash> Type;
};
template <typename KType, typename VType, typename Hash=std::hash<KType>>
class StrongKVCache {
public:
typedef KVCache<KType, VType, std::shared_ptr<VType>, Hash> Type;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment