Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1322)

Unified Diff: chrome/browser/extensions/api/declarative/deduping_factory.h

Issue 14427006: Introduce a Factory for Declarative API objects that performs deduping (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merged with ToT Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/browser/extensions/api/declarative/deduping_factory_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/extensions/api/declarative/deduping_factory.h
diff --git a/chrome/browser/extensions/api/declarative/deduping_factory.h b/chrome/browser/extensions/api/declarative/deduping_factory.h
new file mode 100644
index 0000000000000000000000000000000000000000..462753393760dc4bf00449b5a29a0f115160b943
--- /dev/null
+++ b/chrome/browser/extensions/api/declarative/deduping_factory.h
@@ -0,0 +1,179 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DEDUPING_FACTORY_H__
+#define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DEDUPING_FACTORY_H__
+
+#include <list>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/stl_util.h"
+
+namespace base {
+class Value;
+} // namespace base
+
+namespace extensions {
+
+// Factory class that stores a cache of the last |N| created objects of each
+// kind. These objects need to be immutable, refcounted objects that are derived
+// from BaseClassT. The objects do not need to be RefCountedThreadSafe. If a new
+// instance of an object is created that is identical to a pre-existing object,
+// it is discarded and the pre-existing object is recycled.
+//
+// BaseClassT needs to provide a comparison operations. Like the following:
+//
+// class BaseClassT {
+// virtual bool Equals(const BaseClassT* other) const;
+// };
+//
+// The unit test shows an example.
+template<typename BaseClassT>
+class DedupingFactory {
+ public:
+ // Factory methods for BaseClass instances. |value| contains e.g. the json
+ // dictionary that describes the object to be instantiated. |error| is used
+ // to return error messages in case the extension passed an action that was
+ // syntactically correct but semantically incorrect. |bad_message| is set to
+ // true in case |dict| does not confirm to the validated JSON specification.
+ typedef scoped_refptr<const BaseClassT>
+ (* FactoryMethod)(const std::string& instance_type,
+ const base::Value* /* value */ ,
+ std::string* /* error */,
+ bool* /* bad_message */);
+
+ enum Parameterized {
+ // Two instantiated objects may be different and we need to check for
+ // equality to see whether we can recycle one.
+ IS_PARAMETERIZED,
+ // The objects are not parameterized, i.e. all created instances are the
+ // same and it is sufficient to create a single one.
+ IS_NOT_PARAMETERIZED
+ };
+
+ // Creates a DedupingFactory with a MRU cache of size |max_number_prototypes|
+ // per instance_type. If we find a match within the cache, the factory reuses
+ // that instance instead of creating a new one. The cache size should not be
+ // too large because we probe linearly whether an element is in the cache.
+ explicit DedupingFactory(size_t max_number_prototypes);
+ ~DedupingFactory();
+
+ void RegisterFactoryMethod(const std::string& instance_type,
+ Parameterized parameterized,
+ FactoryMethod factory_method);
+
+ scoped_refptr<const BaseClassT> Instantiate(const std::string& instance_type,
+ const base::Value* value,
+ std::string* error,
+ bool* bad_message);
+
+ void ClearPrototypes();
+
+ private:
+ typedef std::string InstanceType;
+ // Cache of previous prototypes in most-recently-used order. Most recently
+ // used objects are at the end.
+ typedef std::list<scoped_refptr<const BaseClassT> > PrototypeList;
+ typedef base::hash_map<InstanceType, PrototypeList> ExistingPrototypes;
+ typedef base::hash_map<InstanceType, FactoryMethod> FactoryMethods;
+ typedef base::hash_set<InstanceType> ParameterizedTypes;
+
+ const size_t max_number_prototypes_;
+ ExistingPrototypes prototypes_;
+ FactoryMethods factory_methods_;
+ ParameterizedTypes parameterized_types_;
+
+ DISALLOW_COPY_AND_ASSIGN(DedupingFactory);
+};
+
+template<typename BaseClassT>
+DedupingFactory<BaseClassT>::DedupingFactory(size_t max_number_prototypes)
+ : max_number_prototypes_(max_number_prototypes) {}
+
+template<typename BaseClassT>
+DedupingFactory<BaseClassT>::~DedupingFactory() {}
+
+template<typename BaseClassT>
+void DedupingFactory<BaseClassT>::RegisterFactoryMethod(
+ const std::string& instance_type,
+ typename DedupingFactory<BaseClassT>::Parameterized parameterized,
+ FactoryMethod factory_method) {
+ DCHECK(!ContainsKey(factory_methods_, instance_type));
+ factory_methods_[instance_type] = factory_method;
+ if (parameterized == IS_PARAMETERIZED)
+ parameterized_types_.insert(instance_type);
+}
+
+template<typename BaseClassT>
+scoped_refptr<const BaseClassT> DedupingFactory<BaseClassT>::Instantiate(
+ const std::string& instance_type,
+ const base::Value* value,
+ std::string* error,
+ bool* bad_message) {
+ typename FactoryMethods::const_iterator factory_method_iter =
+ factory_methods_.find(instance_type);
+ if (factory_method_iter == factory_methods_.end()) {
+ *error = "Invalid instance type " + instance_type;
+ *bad_message = true;
+ return scoped_refptr<const BaseClassT>();
+ }
+
+ FactoryMethod factory_method = factory_method_iter->second;
+
+ PrototypeList& prototypes = prototypes_[instance_type];
+
+ // We can take a shortcut for objects that are not parameterized. For those
+ // only a single instance may ever exist so we can simplify the creation
+ // logic.
+ if (!ContainsKey(parameterized_types_, instance_type)) {
+ if (prototypes.empty()) {
+ scoped_refptr<const BaseClassT> new_object =
+ (*factory_method)(instance_type, value, error, bad_message);
+ if (!new_object || !error->empty() || *bad_message)
+ return scoped_refptr<const BaseClassT>();
+ prototypes.push_back(new_object);
+ }
+ return prototypes.front();
+ }
+
+ // Handle parameterized objects.
+ scoped_refptr<const BaseClassT> new_object =
+ (*factory_method)(instance_type, value, error, bad_message);
+ if (!new_object || !error->empty() || *bad_message)
+ return scoped_refptr<const BaseClassT>();
+
+ size_t length = 0;
+ for (typename PrototypeList::iterator i = prototypes.begin();
+ i != prototypes.end();
+ ++i) {
+ if ((*i)->Equals(new_object.get())) {
+ // Move the old object to the end of the queue so that it gets
+ // discarded later.
+ scoped_refptr<const BaseClassT> old_object = *i;
+ prototypes.erase(i);
+ prototypes.push_back(old_object);
+ return old_object;
+ }
+ ++length;
+ }
+
+ if (length >= max_number_prototypes_)
+ prototypes.pop_front();
+ prototypes.push_back(new_object);
+
+ return new_object;
+}
+
+template<typename BaseClassT>
+void DedupingFactory<BaseClassT>::ClearPrototypes() {
+ prototypes_.clear();
+}
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DEDUPING_FACTORY_H__
« no previous file with comments | « no previous file | chrome/browser/extensions/api/declarative/deduping_factory_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698