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 |