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

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: 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 DictionaryValue;
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
vabr (Chromium) 2013/04/23 12:22:12 Maybe we should emphasise that this class does not
battre 2013/04/23 14:20:50 Done.
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. |dict| contains 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 base::DictionaryValue* /* dict */ ,
45 std::string* /* error */,
46 bool* /* bad_message */);
47
48 enum Parameterized {
49 // Two instantiated objects may be different and we need to check for
50 // equality to see whether we can recycle one.
51 IS_PARAMETERIZED,
52 // The objects are not parameterized, i.e. all created instances are the
53 // same and it is sufficient to create a single one.
54 IS_NOT_PARAMETERIZED
55 };
56
57 // Creates a DedupingFactory with a MRU cache of size |max_number_prototypes|
58 // per instance_type. If we find a match within the cache, the factory reuses
59 // that instance instead of creating a new one. The cache size should not be
60 // too large because we probe linearly whether an element is in the cache.
61 explicit DedupingFactory(size_t max_number_prototypes);
62 ~DedupingFactory();
63
64 void RegisterFactoryMethod(const std::string& instance_type,
65 Parameterized parameterized,
66 FactoryMethod factory_method);
67
68 scoped_refptr<const BaseClassT> Instantiate(const std::string& instance_type,
69 const base::DictionaryValue* dict,
70 std::string* error,
71 bool* bad_message);
72
73 void ClearPrototypes();
74
75 private:
76 typedef std::string InstanceType;
77 // Cache of previous prototypes in most-recently-used order. Most recently
78 // used objects are at the end.
79 typedef std::list<scoped_refptr<const BaseClassT> > PrototypeList;
80 typedef base::hash_map<InstanceType, PrototypeList> ExistingPrototypes;
81 typedef base::hash_map<InstanceType, FactoryMethod> FactoryMethods;
82 typedef base::hash_set<InstanceType> ParameterizedTypes;
83
84 size_t max_number_prototypes_;
vabr (Chromium) 2013/04/23 12:22:12 This should be at least const, but I would even re
battre 2013/04/23 14:20:50 I have made it const (even though it is pretty unc
vabr (Chromium) 2013/04/23 15:47:23 I don't mean to be a pain in the ass, so feel free
battre 2013/04/29 17:42:34 The point I disliked was this syntax to access the
vabr (Chromium) 2013/04/30 07:33:31 Sure, that's fine with me, no follow-up CL necessa
85 ExistingPrototypes prototypes_;
86 FactoryMethods factory_methods_;
87 ParameterizedTypes parameterized_types_;
88
89 DISALLOW_COPY_AND_ASSIGN(DedupingFactory);
90 };
91
92 template<typename BaseClassT>
93 DedupingFactory<BaseClassT>::DedupingFactory(size_t max_number_prototypes)
94 : max_number_prototypes_(max_number_prototypes) {}
95
96 template<typename BaseClassT>
97 DedupingFactory<BaseClassT>::~DedupingFactory() {}
98
99 template<typename BaseClassT>
100 void DedupingFactory<BaseClassT>::RegisterFactoryMethod(
101 const std::string& instance_type,
102 DedupingFactory<BaseClassT>::Parameterized parameterized,
103 FactoryMethod factory_method) {
104 DCHECK(factory_methods_.find(instance_type) == factory_methods_.end());
vabr (Chromium) 2013/04/23 12:22:12 nit: !ContainsKey(factory_methods_, instance_type)
battre 2013/04/23 14:20:50 Done.
105 factory_methods_[instance_type] = factory_method;
106 if (parameterized == IS_PARAMETERIZED)
107 parameterized_types_.insert(instance_type);
108 }
109
110 template<typename BaseClassT>
111 scoped_refptr<const BaseClassT> DedupingFactory<BaseClassT>::Instantiate(
112 const std::string& instance_type,
113 const base::DictionaryValue* dict,
114 std::string* error,
115 bool* bad_message) {
116 typename FactoryMethods::const_iterator factory_method_iter =
117 factory_methods_.find(instance_type);
118 if (factory_method_iter == factory_methods_.end()) {
119 *error = "Invalid instance type " + instance_type;
120 *bad_message = true;
121 return scoped_refptr<const BaseClassT>();
122 }
123
124 FactoryMethod factory_method = factory_method_iter->second;
125
126 PrototypeList& prototypes = prototypes_[instance_type];
127
128 // We can take a shortcut for objects that are not parameterized. For those
129 // only a single instance may ever exist so we can simplify the creation
130 // logic.
131 if (parameterized_types_.find(instance_type) == parameterized_types_.end()) {
vabr (Chromium) 2013/04/23 12:22:12 nit: !ContainsKey(parametrized_types_, instance_ty
battre 2013/04/23 14:20:50 Done.
132 if (prototypes.empty()) {
133 scoped_refptr<const BaseClassT> new_object =
134 (*factory_method)(dict, error, bad_message);
135 if (!new_object || !error->empty() || *bad_message)
136 return scoped_refptr<const BaseClassT>();
137 prototypes.push_back(new_object);
138 }
139 return prototypes.front();
140 }
141
142 // Handle parameterized objects.
143 scoped_refptr<const BaseClassT> new_object =
144 (*factory_method)(dict, error, bad_message);
145 if (!new_object || !error->empty() || *bad_message)
146 return scoped_refptr<const BaseClassT>();
147
148 size_t length = 0;
149 for (typename PrototypeList::iterator i = prototypes.begin();
150 i != prototypes.end();
151 ++i) {
152 if ((*i)->Equals(new_object.get())) {
153 // Move the old object to the end of the queue so that it gets
154 // discarded later.
155 scoped_refptr<const BaseClassT> old_object = *i;
156 prototypes.erase(i);
157 prototypes.push_back(old_object);
158 return old_object;
159 }
160 ++length;
161 }
162 prototypes.push_back(new_object);
163 ++length;
164
165 if (length > max_number_prototypes_)
166 prototypes.pop_front();
vabr (Chromium) 2013/04/23 12:22:12 If this goes just before the push_back (adjusting
battre 2013/04/23 14:20:50 Done.
167
168 return new_object;
169 }
170
171 template<typename BaseClassT>
172 void DedupingFactory<BaseClassT>::ClearPrototypes() {
173 prototypes_.clear();
174 }
175
176 } // namespace extensions
177
178 #endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DEDUPING_FACTORY_H__
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698