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

Side by Side 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: Generalize DeduplicatingFactory so that it can be used for ContentAttributes as well 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DEDUPING_FACTORY_H__
6 #define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DEDUPING_FACTORY_H__
7
8 #include <list>
9 #include <string>
10
11 #include "base/compiler_specific.h"
12 #include "base/hash_tables.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15
16 namespace base {
17 class Value;
18 } // namespace base
19
20 namespace extensions {
21
22 // Factory class that stores a cache of the last |N| created objects of each
23 // kind. These objects need to be immutable, refcounted objects that are derived
24 // from BaseClassT. If a new instance of an object is created that is identical
25 // to a pre-existing object, it is discarded and the pre-existing object is
26 // recycled.
27 //
28 // BaseClassT needs to provide a comparison operations. Like the following:
29 //
30 // class BaseClassT {
31 // virtual bool Equals(const BaseClassT* other) const;
32 // };
33 //
34 // The unit test shows an example.
35 template<typename BaseClassT>
36 class DedupingFactory {
37 public:
38 // Factory methods for BaseClass instances. |value| contains e.g. the json
39 // dictionary that describes the object to be instantiated. |error| is used
40 // to return error messages in case the extension passed an action that was
41 // syntactically correct but semantically incorrect. |bad_message| is set to
42 // true in case |dict| does not confirm to the validated JSON specification.
43 typedef scoped_refptr<const BaseClassT>
44 (* FactoryMethod)(const std::string& instance_type,
45 const base::Value* /* value */ ,
46 std::string* /* error */,
47 bool* /* bad_message */);
48
49 enum Parameterized {
50 // Two instantiated objects may be different and we need to check for
51 // equality to see whether we can recycle one.
52 IS_PARAMETERIZED,
53 // The objects are not parameterized, i.e. all created instances are the
54 // same and it is sufficient to create a single one.
55 IS_NOT_PARAMETERIZED
56 };
57
58 // Creates a DedupingFactory with a MRU cache of size |max_number_prototypes|
59 // per instance_type. If we find a match within the cache, the factory reuses
60 // that instance instead of creating a new one. The cache size should not be
61 // too large because we probe linearly whether an element is in the cache.
62 explicit DedupingFactory(size_t max_number_prototypes);
63 ~DedupingFactory();
64
65 void RegisterFactoryMethod(const std::string& instance_type,
66 Parameterized parameterized,
67 FactoryMethod factory_method);
68
69 scoped_refptr<const BaseClassT> Instantiate(const std::string& instance_type,
70 const base::Value* value,
71 std::string* error,
72 bool* bad_message);
73
74 void ClearPrototypes();
75
76 private:
77 typedef std::string InstanceType;
78 // Cache of previous prototypes in most-recently-used order. Most recently
79 // used objects are at the end.
80 typedef std::list<scoped_refptr<const BaseClassT> > PrototypeList;
81 typedef base::hash_map<InstanceType, PrototypeList> ExistingPrototypes;
82 typedef base::hash_map<InstanceType, FactoryMethod> FactoryMethods;
83 typedef base::hash_set<InstanceType> ParameterizedTypes;
84
85 size_t max_number_prototypes_;
86 ExistingPrototypes prototypes_;
87 FactoryMethods factory_methods_;
88 ParameterizedTypes parameterized_types_;
89
90 DISALLOW_COPY_AND_ASSIGN(DedupingFactory);
91 };
92
93 template<typename BaseClassT>
94 DedupingFactory<BaseClassT>::DedupingFactory(size_t max_number_prototypes)
95 : max_number_prototypes_(max_number_prototypes) {}
96
97 template<typename BaseClassT>
98 DedupingFactory<BaseClassT>::~DedupingFactory() {}
99
100 template<typename BaseClassT>
101 void DedupingFactory<BaseClassT>::RegisterFactoryMethod(
102 const std::string& instance_type,
103 DedupingFactory<BaseClassT>::Parameterized parameterized,
104 FactoryMethod factory_method) {
105 DCHECK(factory_methods_.find(instance_type) == factory_methods_.end());
106 factory_methods_[instance_type] = factory_method;
107 if (parameterized == IS_PARAMETERIZED)
108 parameterized_types_.insert(instance_type);
109 }
110
111 template<typename BaseClassT>
112 scoped_refptr<const BaseClassT> DedupingFactory<BaseClassT>::Instantiate(
113 const std::string& instance_type,
114 const base::Value* value,
115 std::string* error,
116 bool* bad_message) {
117 typename FactoryMethods::const_iterator factory_method_iter =
118 factory_methods_.find(instance_type);
119 if (factory_method_iter == factory_methods_.end()) {
120 *error = "Invalid instance type " + instance_type;
121 *bad_message = true;
122 return scoped_refptr<const BaseClassT>();
123 }
124
125 FactoryMethod factory_method = factory_method_iter->second;
126
127 PrototypeList& prototypes = prototypes_[instance_type];
128
129 // We can take a shortcut for objects that are not parameterized. For those
130 // only a single instance may ever exist so we can simplify the creation
131 // logic.
132 if (parameterized_types_.find(instance_type) == parameterized_types_.end()) {
133 if (prototypes.empty()) {
134 scoped_refptr<const BaseClassT> new_object =
135 (*factory_method)(instance_type, value, error, bad_message);
136 if (!new_object || !error->empty() || *bad_message)
137 return scoped_refptr<const BaseClassT>();
138 prototypes.push_back(new_object);
139 }
140 return prototypes.front();
141 }
142
143 // Handle parameterized objects.
144 scoped_refptr<const BaseClassT> new_object =
145 (*factory_method)(instance_type, value, error, bad_message);
146 if (!new_object || !error->empty() || *bad_message)
147 return scoped_refptr<const BaseClassT>();
148
149 size_t length = 0;
150 for (typename PrototypeList::iterator i = prototypes.begin();
151 i != prototypes.end();
152 ++i) {
153 if ((*i)->Equals(new_object.get())) {
154 // Move the old object to the end of the queue so that it gets
155 // discarded later.
156 scoped_refptr<const BaseClassT> old_object = *i;
157 prototypes.erase(i);
158 prototypes.push_back(old_object);
159 return old_object;
160 }
161 ++length;
162 }
163 prototypes.push_back(new_object);
164 ++length;
165
166 if (length > max_number_prototypes_)
167 prototypes.pop_front();
168
169 return new_object;
170 }
171
172 template<typename BaseClassT>
173 void DedupingFactory<BaseClassT>::ClearPrototypes() {
174 prototypes_.clear();
175 }
176
177 } // namespace extensions
178
179 #endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DEDUPING_FACTORY_H__
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698