Browse Source

Cpp: Implementing Cache.

pull/567/head
Fredrik Roubert 15 years ago
committed by Mihaela Rosca
parent
commit
d56616b103
3 changed files with 83 additions and 20 deletions
  1. +44
    -7
      cpp/src/re2_cache.cc
  2. +30
    -7
      cpp/src/re2_cache.h
  3. +9
    -6
      cpp/src/re2_cache_test.cc

+ 44
- 7
cpp/src/re2_cache.cc View File

@ -18,21 +18,58 @@
#include <cstddef> #include <cstddef>
#include <string> #include <string>
#include <utility>
#include <re2/re2.h> #include <re2/re2.h>
namespace i18n {
namespace phonenumbers {
#include "base/logging.h"
#include "base/synchronization/lock.h"
using std::string; using std::string;
RE2Cache::RE2Cache(size_t /*max_items*/) {}
RE2Cache::~RE2Cache() {}
// A basic text book string hash function implementation, this one taken from
// The Practice of Programming (Kernighan and Pike 1999). It could be a good
// idea in the future to evaluate how well it actually performs and possibly
// switch to another hash function better suited to this particular use case.
namespace __gnu_cxx {
template<> struct hash<string> {
enum { MULTIPLIER = 31 };
size_t operator()(const string& key) const {
size_t h = 0;
for (const char* p = key.c_str(); *p != '\0'; ++p) {
h *= MULTIPLIER;
h += *p;
}
return h;
}
};
} // namespace __gnu_cxx
namespace i18n {
namespace phonenumbers {
RE2Cache::ScopedAccess::ScopedAccess(RE2Cache* /*cache*/, const string& pattern)
: pattern_(pattern), regexp_(new RE2(pattern_)) {}
RE2Cache::RE2Cache(size_t min_items) : cache_impl_(new CacheImpl(min_items)) {}
RE2Cache::~RE2Cache() {
base::AutoLock l(lock_);
LOG(2) << "Cache entries upon destruction: " << cache_impl_->size();
for (CacheImpl::const_iterator
it = cache_impl_->begin(); it != cache_impl_->end(); ++it) {
delete it->second;
}
}
RE2Cache::ScopedAccess::~ScopedAccess() {}
RE2Cache::ScopedAccess::ScopedAccess(RE2Cache* cache, const string& pattern) {
DCHECK(cache);
base::AutoLock l(cache->lock_);
CacheImpl* const cache_impl = cache->cache_impl_.get();
CacheImpl::const_iterator it = cache_impl->find(pattern);
if (it != cache_impl->end()) {
regexp_ = it->second;
} else {
regexp_ = new RE2(pattern);
cache_impl->insert(make_pair(pattern, regexp_));
}
}
} // namespace phonenumbers } // namespace phonenumbers
} // namespace i18n } // namespace i18n

+ 30
- 7
cpp/src/re2_cache.h View File

@ -14,17 +14,32 @@
// Author: Fredrik Roubert <roubert@google.com> // Author: Fredrik Roubert <roubert@google.com>
// The RE2Cache provides an interface to store RE2 objects in some kind of
// cache. Currently, it doesn't do any caching at all but just provides the
// interface. TODO: Implement caching. ;-)
// RE2Cache is a simple wrapper around hash_map<> to store RE2 objects.
//
// To get a cached RE2 object for a regexp pattern string, create a ScopedAccess
// object with a pointer to the cache object and the pattern string itself as
// constructor parameters. If an RE2 object corresponding to the pattern string
// doesn't already exist, it will be created by the access object constructor.
// The access object implements operator const RE& and can therefore be passed
// as an argument to any function that expects an RE2 object.
//
// RE2Cache cache;
// RE2Cache::ScopedAccess foo(&cache, "foo");
// bool match = RE2::FullMatch("foobar", foo);
#ifndef I18N_PHONENUMBERS_RE2_CACHE_H_ #ifndef I18N_PHONENUMBERS_RE2_CACHE_H_
#define I18N_PHONENUMBERS_RE2_CACHE_H_ #define I18N_PHONENUMBERS_RE2_CACHE_H_
#ifdef __DEPRECATED
#undef __DEPRECATED // Don't warn for using <hash_map>.
#endif
#include <cstddef> #include <cstddef>
#include <hash_map>
#include <string> #include <string>
#include "base/scoped_ptr.h" #include "base/scoped_ptr.h"
#include "base/synchronization/lock.h"
namespace re2 { namespace re2 {
class RE2; class RE2;
@ -35,23 +50,31 @@ namespace phonenumbers {
using re2::RE2; using re2::RE2;
using std::string; using std::string;
using __gnu_cxx::hash_map;
class RE2Cache { class RE2Cache {
private:
typedef hash_map<string, const RE2*> CacheImpl;
public: public:
explicit RE2Cache(size_t max_items);
explicit RE2Cache(size_t min_items);
~RE2Cache(); ~RE2Cache();
class ScopedAccess { class ScopedAccess {
public: public:
ScopedAccess(RE2Cache* cache, const string& pattern); ScopedAccess(RE2Cache* cache, const string& pattern);
~ScopedAccess();
operator const RE2&() const { return *regexp_; } operator const RE2&() const { return *regexp_; }
private: private:
const string pattern_;
scoped_ptr<const RE2> regexp_;
const RE2* regexp_;
friend class RE2CacheTest_AccessConstructor_Test; friend class RE2CacheTest_AccessConstructor_Test;
}; };
private:
base::Lock lock_; // protects cache_impl_
scoped_ptr<CacheImpl> cache_impl_; // protected by lock_
friend class RE2CacheTest_CacheConstructor_Test;
friend class RE2CacheTest_AccessConstructor_Test;
}; };
} // namespace phonenumbers } // namespace phonenumbers


+ 9
- 6
cpp/src/re2_cache_test.cc View File

@ -14,9 +14,6 @@
// Author: Fredrik Roubert <roubert@google.com> // Author: Fredrik Roubert <roubert@google.com>
// Test the wrapper of the cache. The cache functionality itself will be tested
// by the unit test for the cache implementation.
#include <cstddef> #include <cstddef>
#include <string> #include <string>
@ -32,20 +29,26 @@ using std::string;
class RE2CacheTest : public testing::Test { class RE2CacheTest : public testing::Test {
protected: protected:
static const size_t max_items_ = 2;
static const size_t min_items_ = 2;
RE2CacheTest() : cache_(max_items_) {}
RE2CacheTest() : cache_(min_items_) {}
virtual ~RE2CacheTest() {} virtual ~RE2CacheTest() {}
RE2Cache cache_; RE2Cache cache_;
}; };
TEST_F(RE2CacheTest, CacheConstructor) {
ASSERT_TRUE(cache_.cache_impl_ != NULL);
EXPECT_TRUE(cache_.cache_impl_->empty());
}
TEST_F(RE2CacheTest, AccessConstructor) { TEST_F(RE2CacheTest, AccessConstructor) {
static const string foo("foo"); static const string foo("foo");
RE2Cache::ScopedAccess access(&cache_, foo); RE2Cache::ScopedAccess access(&cache_, foo);
EXPECT_EQ(foo, access.pattern_);
EXPECT_TRUE(access.regexp_ != NULL); EXPECT_TRUE(access.regexp_ != NULL);
ASSERT_TRUE(cache_.cache_impl_ != NULL);
EXPECT_EQ(1, cache_.cache_impl_->size());
} }
TEST_F(RE2CacheTest, OperatorRE2) { TEST_F(RE2CacheTest, OperatorRE2) {


Loading…
Cancel
Save