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

Side by Side Diff: components/policy/core/common/schema.cc

Issue 47513018: Make the internal storage of policy::Schemas ref counted. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@chrome-policy-schema-4-new-generate
Patch Set: rebase Created 7 years, 1 month 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/policy/core/common/schema.h" 5 #include "components/policy/core/common/schema.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 if (kSchemaToValueTypeMap[i].schema_type == type_string) { 44 if (kSchemaToValueTypeMap[i].schema_type == type_string) {
45 *type = kSchemaToValueTypeMap[i].value_type; 45 *type = kSchemaToValueTypeMap[i].value_type;
46 return true; 46 return true;
47 } 47 }
48 } 48 }
49 return false; 49 return false;
50 } 50 }
51 51
52 } // namespace 52 } // namespace
53 53
54 // A SchemaOwner can either Wrap() a SchemaData owned elsewhere (currently used 54 // Contains the internal data representation of a Schema. This can either wrap
55 // to wrap the Chrome schema, which is generated at compile time), or it can 55 // a SchemaData owned elsewhere (currently used to wrap the Chrome schema, which
56 // own its own SchemaData. In that case, the InternalStorage class holds the 56 // is generated at compile time), or it can own its own SchemaData.
57 // data referenced by the SchemaData substructures. 57 class Schema::InternalStorage
58 class SchemaOwner::InternalStorage { 58 : public base::RefCountedThreadSafe<InternalStorage> {
59 public: 59 public:
60 ~InternalStorage() {} 60 static scoped_refptr<const InternalStorage> Wrap(const SchemaData* data);
61 61
62 static scoped_ptr<InternalStorage> ParseSchema( 62 static scoped_refptr<const InternalStorage> ParseSchema(
63 const base::DictionaryValue& schema, 63 const base::DictionaryValue& schema,
64 std::string* error); 64 std::string* error);
65 65
66 const SchemaData* schema_data() const { return &schema_data_; } 66 const SchemaData* data() const { return &schema_data_; }
67
68 const SchemaNode* root_node() const {
69 return schema(0);
70 }
71
72 const SchemaNode* schema(int index) const {
73 return schema_data_.schema_nodes + index;
74 }
75
76 const PropertiesNode* properties(int index) const {
77 return schema_data_.properties_nodes + index;
78 }
79
80 const PropertyNode* property(int index) const {
81 return schema_data_.property_nodes + index;
82 }
67 83
68 private: 84 private:
69 InternalStorage() {} 85 friend class base::RefCountedThreadSafe<InternalStorage>;
86
87 InternalStorage();
88 ~InternalStorage();
70 89
71 // Parses the JSON schema in |schema| and returns the index of the 90 // Parses the JSON schema in |schema| and returns the index of the
72 // corresponding SchemaNode in |schema_nodes_|, which gets populated with any 91 // corresponding SchemaNode in |schema_nodes_|, which gets populated with any
73 // necessary intermediate nodes. If |schema| is invalid then -1 is returned 92 // necessary intermediate nodes. If |schema| is invalid then -1 is returned
74 // and |error| is set to the error cause. 93 // and |error| is set to the error cause.
75 int Parse(const base::DictionaryValue& schema, std::string* error); 94 int Parse(const base::DictionaryValue& schema, std::string* error);
76 95
77 // Helper for Parse(). 96 // Helper for Parse().
78 int ParseDictionary(const base::DictionaryValue& schema, std::string* error); 97 int ParseDictionary(const base::DictionaryValue& schema, std::string* error);
79 98
80 // Helper for Parse(). 99 // Helper for Parse().
81 int ParseList(const base::DictionaryValue& schema, std::string* error); 100 int ParseList(const base::DictionaryValue& schema, std::string* error);
82 101
83 SchemaData schema_data_; 102 SchemaData schema_data_;
84 // TODO: compute the sizes of these arrays before filling them up to avoid 103 // TODO: compute the sizes of these arrays before filling them up to avoid
85 // having to resize them. 104 // having to resize them.
86 ScopedVector<std::string> strings_; 105 ScopedVector<std::string> strings_;
87 std::vector<SchemaNode> schema_nodes_; 106 std::vector<SchemaNode> schema_nodes_;
88 std::vector<PropertyNode> property_nodes_; 107 std::vector<PropertyNode> property_nodes_;
89 std::vector<PropertiesNode> properties_nodes_; 108 std::vector<PropertiesNode> properties_nodes_;
90 109
91 DISALLOW_COPY_AND_ASSIGN(InternalStorage); 110 DISALLOW_COPY_AND_ASSIGN(InternalStorage);
92 }; 111 };
93 112
94 Schema::Iterator::Iterator(const SchemaData* data, const PropertiesNode* node) 113 Schema::InternalStorage::InternalStorage() {}
95 : data_(data),
96 it_(data->property_nodes + node->begin),
97 end_(data->property_nodes + node->end) {}
98 114
99 Schema::Iterator::Iterator(const Iterator& iterator) 115 Schema::InternalStorage::~InternalStorage() {}
100 : data_(iterator.data_),
101 it_(iterator.it_),
102 end_(iterator.end_) {}
103 116
104 Schema::Iterator::~Iterator() {} 117 // static
105 118 scoped_refptr<const Schema::InternalStorage> Schema::InternalStorage::Wrap(
106 Schema::Iterator& Schema::Iterator::operator=(const Iterator& iterator) { 119 const SchemaData* data) {
107 data_ = iterator.data_; 120 InternalStorage* storage = new InternalStorage();
108 it_ = iterator.it_; 121 storage->schema_data_.schema_nodes = data->schema_nodes;
109 end_ = iterator.end_; 122 storage->schema_data_.property_nodes = data->property_nodes;
110 return *this; 123 storage->schema_data_.properties_nodes = data->properties_nodes;
111 } 124 return storage;
112
113 bool Schema::Iterator::IsAtEnd() const {
114 return it_ == end_;
115 }
116
117 void Schema::Iterator::Advance() {
118 ++it_;
119 }
120
121 const char* Schema::Iterator::key() const {
122 return it_->key;
123 }
124
125 Schema Schema::Iterator::schema() const {
126 return Schema(data_, data_->schema_nodes + it_->schema);
127 }
128
129 Schema::Schema() : data_(NULL), node_(NULL) {}
130
131 Schema::Schema(const SchemaData* data, const SchemaNode* node)
132 : data_(data), node_(node) {}
133
134 Schema::Schema(const Schema& schema)
135 : data_(schema.data_), node_(schema.node_) {}
136
137 Schema& Schema::operator=(const Schema& schema) {
138 data_ = schema.data_;
139 node_ = schema.node_;
140 return *this;
141 }
142
143 base::Value::Type Schema::type() const {
144 CHECK(valid());
145 return node_->type;
146 }
147
148 Schema::Iterator Schema::GetPropertiesIterator() const {
149 CHECK(valid());
150 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
151 return Iterator(data_, data_->properties_nodes + node_->extra);
152 }
153
154 namespace {
155
156 bool CompareKeys(const PropertyNode& node, const std::string& key) {
157 return node.key < key;
158 }
159
160 } // namespace
161
162 Schema Schema::GetKnownProperty(const std::string& key) const {
163 CHECK(valid());
164 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
165 const PropertiesNode* node = data_->properties_nodes + node_->extra;
166 const PropertyNode* begin = data_->property_nodes + node->begin;
167 const PropertyNode* end = data_->property_nodes + node->end;
168 const PropertyNode* it = std::lower_bound(begin, end, key, CompareKeys);
169 if (it != end && it->key == key)
170 return Schema(data_, data_->schema_nodes + it->schema);
171 return Schema();
172 }
173
174 Schema Schema::GetAdditionalProperties() const {
175 CHECK(valid());
176 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
177 const PropertiesNode* node = data_->properties_nodes + node_->extra;
178 if (node->additional == kInvalid)
179 return Schema();
180 return Schema(data_, data_->schema_nodes + node->additional);
181 }
182
183 Schema Schema::GetProperty(const std::string& key) const {
184 Schema schema = GetKnownProperty(key);
185 return schema.valid() ? schema : GetAdditionalProperties();
186 }
187
188 Schema Schema::GetItems() const {
189 CHECK(valid());
190 CHECK_EQ(base::Value::TYPE_LIST, type());
191 if (node_->extra == kInvalid)
192 return Schema();
193 return Schema(data_, data_->schema_nodes + node_->extra);
194 }
195
196 SchemaOwner::SchemaOwner(const SchemaData* data,
197 scoped_ptr<InternalStorage> storage)
198 : storage_(storage.Pass()), data_(data) {}
199
200 SchemaOwner::~SchemaOwner() {}
201
202 Schema SchemaOwner::schema() const {
203 // data_->schema_nodes[0] is the root node.
204 return Schema(data_, data_->schema_nodes);
205 } 125 }
206 126
207 // static 127 // static
208 scoped_ptr<SchemaOwner> SchemaOwner::Wrap(const SchemaData* data) { 128 scoped_refptr<const Schema::InternalStorage>
209 return make_scoped_ptr(new SchemaOwner(data, scoped_ptr<InternalStorage>())); 129 Schema::InternalStorage::ParseSchema(const base::DictionaryValue& schema,
210 } 130 std::string* error) {
211 131 scoped_refptr<InternalStorage> storage = new InternalStorage();
212 // static
213 scoped_ptr<SchemaOwner> SchemaOwner::Parse(const std::string& content,
214 std::string* error) {
215 // Validate as a generic JSON schema.
216 scoped_ptr<base::DictionaryValue> dict =
217 JSONSchemaValidator::IsValidSchema(content, error);
218 if (!dict)
219 return scoped_ptr<SchemaOwner>();
220
221 // Validate the main type.
222 std::string string_value;
223 if (!dict->GetString(json_schema_constants::kType, &string_value) ||
224 string_value != json_schema_constants::kObject) {
225 *error =
226 "The main schema must have a type attribute with \"object\" value.";
227 return scoped_ptr<SchemaOwner>();
228 }
229
230 // Checks for invalid attributes at the top-level.
231 if (dict->HasKey(json_schema_constants::kAdditionalProperties) ||
232 dict->HasKey(json_schema_constants::kPatternProperties)) {
233 *error = "\"additionalProperties\" and \"patternProperties\" are not "
234 "supported at the main schema.";
235 return scoped_ptr<SchemaOwner>();
236 }
237
238 scoped_ptr<InternalStorage> storage =
239 InternalStorage::ParseSchema(*dict, error);
240 if (!storage)
241 return scoped_ptr<SchemaOwner>();
242 const SchemaData* data = storage->schema_data();
243 return make_scoped_ptr(new SchemaOwner(data, storage.Pass()));
244 }
245
246 // static
247 scoped_ptr<SchemaOwner::InternalStorage>
248 SchemaOwner::InternalStorage::ParseSchema(const base::DictionaryValue& schema,
249 std::string* error) {
250 scoped_ptr<InternalStorage> storage(new InternalStorage);
251 if (storage->Parse(schema, error) == kInvalid) 132 if (storage->Parse(schema, error) == kInvalid)
252 return scoped_ptr<InternalStorage>(); 133 return NULL;
253 SchemaData* data = &storage->schema_data_; 134 SchemaData* data = &storage->schema_data_;
254 data->schema_nodes = vector_as_array(&storage->schema_nodes_); 135 data->schema_nodes = vector_as_array(&storage->schema_nodes_);
255 data->property_nodes = vector_as_array(&storage->property_nodes_); 136 data->property_nodes = vector_as_array(&storage->property_nodes_);
256 data->properties_nodes = vector_as_array(&storage->properties_nodes_); 137 data->properties_nodes = vector_as_array(&storage->properties_nodes_);
257 return storage.Pass(); 138 return storage;
258 } 139 }
259 140
260 int SchemaOwner::InternalStorage::Parse(const base::DictionaryValue& schema, 141 int Schema::InternalStorage::Parse(const base::DictionaryValue& schema,
261 std::string* error) { 142 std::string* error) {
262 std::string type_string; 143 std::string type_string;
263 if (!schema.GetString(json_schema_constants::kType, &type_string)) { 144 if (!schema.GetString(json_schema_constants::kType, &type_string)) {
264 *error = "The schema type must be declared."; 145 *error = "The schema type must be declared.";
265 return kInvalid; 146 return kInvalid;
266 } 147 }
267 148
268 base::Value::Type type = base::Value::TYPE_NULL; 149 base::Value::Type type = base::Value::TYPE_NULL;
269 if (!SchemaTypeToValueType(type_string, &type)) { 150 if (!SchemaTypeToValueType(type_string, &type)) {
270 *error = "Type not supported: " + type_string; 151 *error = "Type not supported: " + type_string;
271 return kInvalid; 152 return kInvalid;
272 } 153 }
273 154
274 if (type == base::Value::TYPE_DICTIONARY) 155 if (type == base::Value::TYPE_DICTIONARY)
275 return ParseDictionary(schema, error); 156 return ParseDictionary(schema, error);
276 if (type == base::Value::TYPE_LIST) 157 if (type == base::Value::TYPE_LIST)
277 return ParseList(schema, error); 158 return ParseList(schema, error);
278 159
279 int index = static_cast<int>(schema_nodes_.size()); 160 int index = static_cast<int>(schema_nodes_.size());
280 schema_nodes_.push_back(SchemaNode()); 161 schema_nodes_.push_back(SchemaNode());
281 SchemaNode& node = schema_nodes_.back(); 162 SchemaNode& node = schema_nodes_.back();
282 node.type = type; 163 node.type = type;
283 node.extra = kInvalid; 164 node.extra = kInvalid;
284 return index; 165 return index;
285 } 166 }
286 167
287 // static 168 // static
288 int SchemaOwner::InternalStorage::ParseDictionary( 169 int Schema::InternalStorage::ParseDictionary(
289 const base::DictionaryValue& schema, 170 const base::DictionaryValue& schema,
290 std::string* error) { 171 std::string* error) {
291 // Note: recursive calls to Parse() invalidate iterators and references into 172 // Note: recursive calls to Parse() invalidate iterators and references into
292 // the vectors. 173 // the vectors.
293 174
294 // Reserve an index for this dictionary at the front, so that the root node 175 // Reserve an index for this dictionary at the front, so that the root node
295 // is at index 0. 176 // is at index 0.
296 int schema_index = static_cast<int>(schema_nodes_.size()); 177 int schema_index = static_cast<int>(schema_nodes_.size());
297 schema_nodes_.push_back(SchemaNode()); 178 schema_nodes_.push_back(SchemaNode());
298 179
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 properties_nodes_[extra].begin = base_index; 216 properties_nodes_[extra].begin = base_index;
336 properties_nodes_[extra].end = index; 217 properties_nodes_[extra].end = index;
337 } 218 }
338 219
339 schema_nodes_[schema_index].type = base::Value::TYPE_DICTIONARY; 220 schema_nodes_[schema_index].type = base::Value::TYPE_DICTIONARY;
340 schema_nodes_[schema_index].extra = extra; 221 schema_nodes_[schema_index].extra = extra;
341 return schema_index; 222 return schema_index;
342 } 223 }
343 224
344 // static 225 // static
345 int SchemaOwner::InternalStorage::ParseList(const base::DictionaryValue& schema, 226 int Schema::InternalStorage::ParseList(const base::DictionaryValue& schema,
346 std::string* error) { 227 std::string* error) {
347 const base::DictionaryValue* dict = NULL; 228 const base::DictionaryValue* dict = NULL;
348 if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) { 229 if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) {
349 *error = "Arrays must declare a single schema for their items."; 230 *error = "Arrays must declare a single schema for their items.";
350 return kInvalid; 231 return kInvalid;
351 } 232 }
352 int extra = Parse(*dict, error); 233 int extra = Parse(*dict, error);
353 if (extra == kInvalid) 234 if (extra == kInvalid)
354 return kInvalid; 235 return kInvalid;
355 int index = static_cast<int>(schema_nodes_.size()); 236 int index = static_cast<int>(schema_nodes_.size());
356 schema_nodes_.push_back(SchemaNode()); 237 schema_nodes_.push_back(SchemaNode());
357 schema_nodes_[index].type = base::Value::TYPE_LIST; 238 schema_nodes_[index].type = base::Value::TYPE_LIST;
358 schema_nodes_[index].extra = extra; 239 schema_nodes_[index].extra = extra;
359 return index; 240 return index;
360 } 241 }
361 242
243 Schema::Iterator::Iterator(const scoped_refptr<const InternalStorage>& storage,
244 const PropertiesNode* node)
245 : storage_(storage),
246 it_(storage->property(node->begin)),
247 end_(storage->property(node->end)) {}
248
249 Schema::Iterator::Iterator(const Iterator& iterator)
250 : storage_(iterator.storage_),
251 it_(iterator.it_),
252 end_(iterator.end_) {}
253
254 Schema::Iterator::~Iterator() {}
255
256 Schema::Iterator& Schema::Iterator::operator=(const Iterator& iterator) {
257 storage_ = iterator.storage_;
258 it_ = iterator.it_;
259 end_ = iterator.end_;
260 return *this;
261 }
262
263 bool Schema::Iterator::IsAtEnd() const {
264 return it_ == end_;
265 }
266
267 void Schema::Iterator::Advance() {
268 ++it_;
269 }
270
271 const char* Schema::Iterator::key() const {
272 return it_->key;
273 }
274
275 Schema Schema::Iterator::schema() const {
276 return Schema(storage_, storage_->schema(it_->schema));
277 }
278
279 Schema::Schema() : node_(NULL) {}
280
281 Schema::Schema(const scoped_refptr<const InternalStorage>& storage,
282 const SchemaNode* node)
283 : storage_(storage), node_(node) {}
284
285 Schema::Schema(const Schema& schema)
286 : storage_(schema.storage_), node_(schema.node_) {}
287
288 Schema::~Schema() {}
289
290 Schema& Schema::operator=(const Schema& schema) {
291 storage_ = schema.storage_;
292 node_ = schema.node_;
293 return *this;
294 }
295
296 // static
297 Schema Schema::Wrap(const SchemaData* data) {
298 scoped_refptr<const InternalStorage> storage = InternalStorage::Wrap(data);
299 return Schema(storage, storage->root_node());
300 }
301
302 // static
303 Schema Schema::Parse(const std::string& content, std::string* error) {
304 // Validate as a generic JSON schema.
305 scoped_ptr<base::DictionaryValue> dict =
306 JSONSchemaValidator::IsValidSchema(content, error);
307 if (!dict)
308 return Schema();
309
310 // Validate the main type.
311 std::string string_value;
312 if (!dict->GetString(json_schema_constants::kType, &string_value) ||
313 string_value != json_schema_constants::kObject) {
314 *error =
315 "The main schema must have a type attribute with \"object\" value.";
316 return Schema();
317 }
318
319 // Checks for invalid attributes at the top-level.
320 if (dict->HasKey(json_schema_constants::kAdditionalProperties) ||
321 dict->HasKey(json_schema_constants::kPatternProperties)) {
322 *error = "\"additionalProperties\" and \"patternProperties\" are not "
323 "supported at the main schema.";
324 return Schema();
325 }
326
327 scoped_refptr<const InternalStorage> storage =
328 InternalStorage::ParseSchema(*dict, error);
329 if (!storage)
330 return Schema();
331 return Schema(storage, storage->root_node());
332 }
333
334 base::Value::Type Schema::type() const {
335 CHECK(valid());
336 return node_->type;
337 }
338
339 Schema::Iterator Schema::GetPropertiesIterator() const {
340 CHECK(valid());
341 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
342 return Iterator(storage_, storage_->properties(node_->extra));
343 }
344
345 namespace {
346
347 bool CompareKeys(const PropertyNode& node, const std::string& key) {
348 return node.key < key;
349 }
350
351 } // namespace
352
353 Schema Schema::GetKnownProperty(const std::string& key) const {
354 CHECK(valid());
355 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
356 const PropertiesNode* node = storage_->properties(node_->extra);
357 const PropertyNode* begin = storage_->property(node->begin);
358 const PropertyNode* end = storage_->property(node->end);
359 const PropertyNode* it = std::lower_bound(begin, end, key, CompareKeys);
360 if (it != end && it->key == key)
361 return Schema(storage_, storage_->schema(it->schema));
362 return Schema();
363 }
364
365 Schema Schema::GetAdditionalProperties() const {
366 CHECK(valid());
367 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
368 const PropertiesNode* node = storage_->properties(node_->extra);
369 if (node->additional == kInvalid)
370 return Schema();
371 return Schema(storage_, storage_->schema(node->additional));
372 }
373
374 Schema Schema::GetProperty(const std::string& key) const {
375 Schema schema = GetKnownProperty(key);
376 return schema.valid() ? schema : GetAdditionalProperties();
377 }
378
379 Schema Schema::GetItems() const {
380 CHECK(valid());
381 CHECK_EQ(base::Value::TYPE_LIST, type());
382 if (node_->extra == kInvalid)
383 return Schema();
384 return Schema(storage_, storage_->schema(node_->extra));
385 }
386
362 } // namespace policy 387 } // namespace policy
OLDNEW
« no previous file with comments | « components/policy/core/common/schema.h ('k') | components/policy/core/common/schema_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698