Chromium Code Reviews| Index: components/policy/core/common/schema.cc |
| diff --git a/components/policy/core/common/schema.cc b/components/policy/core/common/schema.cc |
| index b3e63d7f3b263e4e645baaeea9e1cb0ec58e5823..40c787565ab41a88bc4d6a02d9b130d5ec08e422 100644 |
| --- a/components/policy/core/common/schema.cc |
| +++ b/components/policy/core/common/schema.cc |
| @@ -5,17 +5,26 @@ |
| #include "components/policy/core/common/schema.h" |
| #include <algorithm> |
| +#include <vector> |
| #include "base/compiler_specific.h" |
| #include "base/logging.h" |
| +#include "base/memory/scoped_vector.h" |
| #include "components/json_schema/json_schema_constants.h" |
| #include "components/json_schema/json_schema_validator.h" |
| #include "components/policy/core/common/schema_internal.h" |
| namespace policy { |
| +using internal::PropertiesNode; |
| +using internal::PropertyNode; |
| +using internal::SchemaData; |
| +using internal::SchemaNode; |
| + |
| namespace { |
| +const int kInvalid = -1; |
| + |
| bool SchemaTypeToValueType(const std::string& type_string, |
| base::Value::Type* type) { |
| // Note: "any" is not an accepted type. |
| @@ -42,17 +51,41 @@ bool SchemaTypeToValueType(const std::string& type_string, |
| } // namespace |
| -Schema::Iterator::Iterator(const internal::PropertiesNode* properties) |
| - : it_(properties->begin), |
| - end_(properties->end) {} |
| +// A SchemaOwner can either Wrap() a SchemaData owned elsewhere (currently used |
| +// to wrap the Chrome schema, which is generated at compile time), or it can |
| +// own its own SchemaData. In that case, the Internal class holds the data |
| +// referenced by the SchemaData substructures. |
| +class SchemaOwner::Internal { |
| + public: |
| + Internal() {} |
| + ~Internal() {} |
| + |
| + SchemaData schema_data; |
| + // TODO: compute the sizes of these arrays before filling them up to avoid |
| + // having to resize them. |
| + ScopedVector<std::string> strings; |
| + std::vector<SchemaNode> schema_nodes; |
| + std::vector<PropertyNode> property_nodes; |
| + std::vector<PropertiesNode> properties_nodes; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(Internal); |
| +}; |
| + |
| +Schema::Iterator::Iterator(const SchemaData* data, const PropertiesNode* node) |
| + : data_(data), |
| + it_(data->property_nodes + node->begin), |
| + end_(data->property_nodes + node->end) {} |
| Schema::Iterator::Iterator(const Iterator& iterator) |
| - : it_(iterator.it_), |
| + : data_(iterator.data_), |
| + it_(iterator.it_), |
| end_(iterator.end_) {} |
| Schema::Iterator::~Iterator() {} |
| Schema::Iterator& Schema::Iterator::operator=(const Iterator& iterator) { |
| + data_ = iterator.data_; |
| it_ = iterator.it_; |
| end_ = iterator.end_; |
| return *this; |
| @@ -71,35 +104,37 @@ const char* Schema::Iterator::key() const { |
| } |
| Schema Schema::Iterator::schema() const { |
| - return Schema(it_->schema); |
| + return Schema(data_, data_->schema_nodes + it_->schema); |
| } |
| -Schema::Schema() : schema_(NULL) {} |
| +Schema::Schema() : data_(NULL), node_(NULL) {} |
| -Schema::Schema(const internal::SchemaNode* schema) : schema_(schema) {} |
| +Schema::Schema(const SchemaData* data, const SchemaNode* node) |
| + : data_(data), node_(node) {} |
| -Schema::Schema(const Schema& schema) : schema_(schema.schema_) {} |
| +Schema::Schema(const Schema& schema) |
| + : data_(schema.data_), node_(schema.node_) {} |
| Schema& Schema::operator=(const Schema& schema) { |
| - schema_ = schema.schema_; |
| + data_ = schema.data_; |
| + node_ = schema.node_; |
| return *this; |
| } |
| base::Value::Type Schema::type() const { |
| CHECK(valid()); |
| - return schema_->type; |
| + return node_->type; |
| } |
| Schema::Iterator Schema::GetPropertiesIterator() const { |
| CHECK(valid()); |
| CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); |
| - return Iterator( |
| - static_cast<const internal::PropertiesNode*>(schema_->extra)); |
| + return Iterator(data_, data_->properties_nodes + node_->extra); |
| } |
| namespace { |
| -bool CompareKeys(const internal::PropertyNode& node, const std::string& key) { |
| +bool CompareKeys(const PropertyNode& node, const std::string& key) { |
| return node.key < key; |
| } |
| @@ -108,20 +143,22 @@ bool CompareKeys(const internal::PropertyNode& node, const std::string& key) { |
| Schema Schema::GetKnownProperty(const std::string& key) const { |
| CHECK(valid()); |
| CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); |
| - const internal::PropertiesNode* properties_node = |
| - static_cast<const internal::PropertiesNode*>(schema_->extra); |
| - const internal::PropertyNode* it = std::lower_bound( |
| - properties_node->begin, properties_node->end, key, CompareKeys); |
| - if (it != properties_node->end && it->key == key) |
| - return Schema(it->schema); |
| + const PropertiesNode* node = data_->properties_nodes + node_->extra; |
| + const PropertyNode* begin = data_->property_nodes + node->begin; |
| + const PropertyNode* end = data_->property_nodes + node->end; |
| + const PropertyNode* it = std::lower_bound(begin, end, key, CompareKeys); |
| + if (it != end && it->key == key) |
| + return Schema(data_, data_->schema_nodes + it->schema); |
| return Schema(); |
| } |
| Schema Schema::GetAdditionalProperties() const { |
| CHECK(valid()); |
| CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); |
| - return Schema( |
| - static_cast<const internal::PropertiesNode*>(schema_->extra)->additional); |
| + const PropertiesNode* node = data_->properties_nodes + node_->extra; |
| + if (node->additional == kInvalid) |
| + return Schema(); |
| + return Schema(data_, data_->schema_nodes + node->additional); |
| } |
| Schema Schema::GetProperty(const std::string& key) const { |
| @@ -132,19 +169,24 @@ Schema Schema::GetProperty(const std::string& key) const { |
| Schema Schema::GetItems() const { |
| CHECK(valid()); |
| CHECK_EQ(base::Value::TYPE_LIST, type()); |
| - return Schema(static_cast<const internal::SchemaNode*>(schema_->extra)); |
| + if (node_->extra == kInvalid) |
| + return Schema(); |
| + return Schema(data_, data_->schema_nodes + node_->extra); |
| } |
| -SchemaOwner::SchemaOwner(const internal::SchemaNode* root) : root_(root) {} |
| +SchemaOwner::SchemaOwner(const SchemaData* data, scoped_ptr<Internal> internal) |
| + : internal_(internal.Pass()), data_(data) {} |
| + |
| +SchemaOwner::~SchemaOwner() {} |
| -SchemaOwner::~SchemaOwner() { |
| - for (size_t i = 0; i < property_nodes_.size(); ++i) |
| - delete[] property_nodes_[i]; |
| +Schema SchemaOwner::schema() const { |
| + // data_->schema_nodes[0] is the root node. |
| + return Schema(data_, data_->schema_nodes + 0); |
|
pastarmovj
2013/10/22 09:30:46
I don't think this "+ 0" really adds much value he
Joao da Silva
2013/10/22 12:53:27
Done.
|
| } |
| // static |
| -scoped_ptr<SchemaOwner> SchemaOwner::Wrap(const internal::SchemaNode* schema) { |
| - return scoped_ptr<SchemaOwner>(new SchemaOwner(schema)); |
| +scoped_ptr<SchemaOwner> SchemaOwner::Wrap(const SchemaData* data) { |
| + return make_scoped_ptr(new SchemaOwner(data, scoped_ptr<Internal>())); |
| } |
| // static |
| @@ -173,106 +215,123 @@ scoped_ptr<SchemaOwner> SchemaOwner::Parse(const std::string& content, |
| return scoped_ptr<SchemaOwner>(); |
| } |
| - scoped_ptr<SchemaOwner> impl(new SchemaOwner(NULL)); |
| - impl->root_ = impl->Parse(*dict, error); |
| - if (!impl->root_) |
| - impl.reset(); |
| - return impl.PassAs<SchemaOwner>(); |
| + scoped_ptr<Internal> internal(new Internal); |
| + if (Parse(*dict, error, internal.get()) == kInvalid) |
| + return scoped_ptr<SchemaOwner>(); |
| + SchemaData* data = &internal->schema_data; |
| + data->schema_nodes = vector_as_array(&internal->schema_nodes); |
| + data->property_nodes = vector_as_array(&internal->property_nodes); |
| + data->properties_nodes = vector_as_array(&internal->properties_nodes); |
| + return make_scoped_ptr(new SchemaOwner(data, internal.Pass())); |
| } |
| -const internal::SchemaNode* SchemaOwner::Parse( |
| +// static |
| +int SchemaOwner::Parse( |
| const base::DictionaryValue& schema, |
| - std::string* error) { |
| + std::string* error, |
| + Internal* internal) { |
| std::string type_string; |
| if (!schema.GetString(json_schema_constants::kType, &type_string)) { |
| *error = "The schema type must be declared."; |
| - return NULL; |
| + return kInvalid; |
| } |
| base::Value::Type type = base::Value::TYPE_NULL; |
| if (!SchemaTypeToValueType(type_string, &type)) { |
| *error = "Type not supported: " + type_string; |
| - return NULL; |
| + return kInvalid; |
| } |
| if (type == base::Value::TYPE_DICTIONARY) |
| - return ParseDictionary(schema, error); |
| + return ParseDictionary(schema, error, internal); |
| if (type == base::Value::TYPE_LIST) |
| - return ParseList(schema, error); |
| - |
| - internal::SchemaNode* node = new internal::SchemaNode; |
| - node->type = type; |
| - node->extra = NULL; |
| - schema_nodes_.push_back(node); |
| - return node; |
| + return ParseList(schema, error, internal); |
| + |
| + int index = static_cast<int>(internal->schema_nodes.size()); |
| + internal->schema_nodes.push_back(SchemaNode()); |
| + SchemaNode& node = internal->schema_nodes.back(); |
| + node.type = type; |
| + node.extra = kInvalid; |
| + return index; |
| } |
| -const internal::SchemaNode* SchemaOwner::ParseDictionary( |
| +// static |
| +int SchemaOwner::ParseDictionary( |
| const base::DictionaryValue& schema, |
| - std::string* error) { |
| - internal::PropertiesNode* properties_node = new internal::PropertiesNode; |
| - properties_node->begin = NULL; |
| - properties_node->end = NULL; |
| - properties_node->additional = NULL; |
| - properties_nodes_.push_back(properties_node); |
| + std::string* error, |
| + Internal* internal) { |
| + // Note: recursive calls to Parse() invalidate iterators and references into |
| + // the vectors. |
| + |
| + // Reserve an index for this dictionary at the front, so that the root node |
| + // is at index 0. |
| + int index = static_cast<int>(internal->schema_nodes.size()); |
| + internal->schema_nodes.push_back(SchemaNode()); |
| + |
| + int extra = static_cast<int>(internal->properties_nodes.size()); |
| + internal->properties_nodes.push_back(PropertiesNode()); |
| + internal->properties_nodes[extra].begin = kInvalid; |
| + internal->properties_nodes[extra].end = kInvalid; |
| + internal->properties_nodes[extra].additional = kInvalid; |
| const base::DictionaryValue* dict = NULL; |
|
dconnelly
2013/10/22 11:55:52
Can these be moved closer to their first use?
Joao da Silva
2013/10/22 12:53:27
Done.
|
| const base::DictionaryValue* properties = NULL; |
| + |
| + if (schema.GetDictionary(json_schema_constants::kAdditionalProperties, |
| + &dict)) { |
| + int additional = Parse(*dict, error, internal); |
| + if (additional == kInvalid) |
| + return kInvalid; |
| + internal->properties_nodes[extra].additional = additional; |
| + } |
| + |
| if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) { |
| - internal::PropertyNode* property_nodes = |
| - new internal::PropertyNode[properties->size()]; |
| - property_nodes_.push_back(property_nodes); |
| + int base_index = static_cast<int>(internal->property_nodes.size()); |
| + // This reserves nodes for all of the |properties|, and makes sure they |
| + // are contiguous. Recursive calls to Parse() will append after these |
| + // elements. |
| + internal->property_nodes.resize(base_index + properties->size()); |
| - size_t index = 0; |
| + int index = base_index; |
|
pastarmovj
2013/10/22 09:30:46
Just a warning that this redefines the variable in
Joao da Silva
2013/10/22 12:53:27
Renamed the outer "index" to "schema_index".
|
| for (base::DictionaryValue::Iterator it(*properties); |
| !it.IsAtEnd(); it.Advance(), ++index) { |
| // This should have been verified by the JSONSchemaValidator. |
| CHECK(it.value().GetAsDictionary(&dict)); |
| - const internal::SchemaNode* sub_schema = Parse(*dict, error); |
| - if (!sub_schema) |
| - return NULL; |
| - std::string* key = new std::string(it.key()); |
| - keys_.push_back(key); |
| - property_nodes[index].key = key->c_str(); |
| - property_nodes[index].schema = sub_schema; |
| + int extra = Parse(*dict, error, internal); |
| + if (extra == kInvalid) |
| + return kInvalid; |
| + internal->strings.push_back(new std::string(it.key())); |
| + internal->property_nodes[index].key = internal->strings.back()->c_str(); |
| + internal->property_nodes[index].schema = extra; |
| } |
| - CHECK_EQ(properties->size(), index); |
| - properties_node->begin = property_nodes; |
| - properties_node->end = property_nodes + index; |
| - } |
| - |
| - if (schema.GetDictionary(json_schema_constants::kAdditionalProperties, |
| - &dict)) { |
| - const internal::SchemaNode* sub_schema = Parse(*dict, error); |
| - if (!sub_schema) |
| - return NULL; |
| - properties_node->additional = sub_schema; |
| + CHECK_EQ(static_cast<int>(properties->size()), index - base_index); |
| + internal->properties_nodes[extra].begin = base_index; |
| + internal->properties_nodes[extra].end = index; |
| } |
| - internal::SchemaNode* schema_node = new internal::SchemaNode; |
| - schema_node->type = base::Value::TYPE_DICTIONARY; |
| - schema_node->extra = properties_node; |
| - schema_nodes_.push_back(schema_node); |
| - return schema_node; |
| + internal->schema_nodes[index].type = base::Value::TYPE_DICTIONARY; |
| + internal->schema_nodes[index].extra = extra; |
| + return index; |
| } |
| -const internal::SchemaNode* SchemaOwner::ParseList( |
| +// static |
| +int SchemaOwner::ParseList( |
| const base::DictionaryValue& schema, |
| - std::string* error) { |
| + std::string* error, |
| + Internal* internal) { |
| const base::DictionaryValue* dict = NULL; |
| if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) { |
| *error = "Arrays must declare a single schema for their items."; |
| - return NULL; |
| + return kInvalid; |
| } |
| - const internal::SchemaNode* items_schema_node = Parse(*dict, error); |
| - if (!items_schema_node) |
| - return NULL; |
| - |
| - internal::SchemaNode* schema_node = new internal::SchemaNode; |
| - schema_node->type = base::Value::TYPE_LIST; |
| - schema_node->extra = items_schema_node; |
| - schema_nodes_.push_back(schema_node); |
| - return schema_node; |
| + int extra = Parse(*dict, error, internal); |
| + if (extra == kInvalid) |
| + return kInvalid; |
| + int index = static_cast<int>(internal->schema_nodes.size()); |
| + internal->schema_nodes.push_back(SchemaNode()); |
| + internal->schema_nodes[index].type = base::Value::TYPE_LIST; |
| + internal->schema_nodes[index].extra = extra; |
| + return index; |
| } |
| } // namespace policy |