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..3830bc149bcf1cfbe95363db00a3e8f460e30606 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,60 @@ 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 InternalStorage class holds the |
+// data referenced by the SchemaData substructures. |
+class SchemaOwner::InternalStorage { |
+ public: |
+ ~InternalStorage() {} |
+ |
+ static scoped_ptr<InternalStorage> ParseSchema( |
+ const base::DictionaryValue& schema, |
+ std::string* error); |
+ |
+ const SchemaData* schema_data() const { return &schema_data_; } |
+ |
+ private: |
+ InternalStorage() {} |
+ |
+ // Parses the JSON schema in |schema| and returns the index of the |
+ // corresponding SchemaNode in |schema_nodes_|, which gets populated with any |
+ // necessary intermediate nodes. If |schema| is invalid then -1 is returned |
+ // and |error| is set to the error cause. |
+ int Parse(const base::DictionaryValue& schema, std::string* error); |
+ |
+ // Helper for Parse(). |
+ int ParseDictionary(const base::DictionaryValue& schema, std::string* error); |
+ |
+ // Helper for Parse(). |
+ int ParseList(const base::DictionaryValue& schema, std::string* error); |
+ |
+ 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_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(InternalStorage); |
+}; |
+ |
+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 +123,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 +162,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 +188,25 @@ 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<InternalStorage> storage) |
+ : storage_(storage.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); |
} |
// 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<InternalStorage>())); |
} |
// static |
@@ -173,26 +235,40 @@ 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<InternalStorage> storage = |
+ InternalStorage::ParseSchema(*dict, error); |
+ if (!storage) |
+ return scoped_ptr<SchemaOwner>(); |
+ const SchemaData* data = storage->schema_data(); |
+ return make_scoped_ptr(new SchemaOwner(data, storage.Pass())); |
} |
-const internal::SchemaNode* SchemaOwner::Parse( |
- const base::DictionaryValue& schema, |
- std::string* error) { |
+// static |
+scoped_ptr<SchemaOwner::InternalStorage> |
+SchemaOwner::InternalStorage::ParseSchema(const base::DictionaryValue& schema, |
+ std::string* error) { |
+ scoped_ptr<InternalStorage> storage(new InternalStorage); |
+ if (storage->Parse(schema, error) == kInvalid) |
+ return scoped_ptr<InternalStorage>(); |
+ SchemaData* data = &storage->schema_data_; |
+ data->schema_nodes = vector_as_array(&storage->schema_nodes_); |
+ data->property_nodes = vector_as_array(&storage->property_nodes_); |
+ data->properties_nodes = vector_as_array(&storage->properties_nodes_); |
+ return storage.Pass(); |
+} |
+ |
+int SchemaOwner::InternalStorage::Parse(const base::DictionaryValue& schema, |
+ std::string* error) { |
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) |
@@ -200,79 +276,87 @@ const internal::SchemaNode* SchemaOwner::Parse( |
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; |
+ int index = static_cast<int>(schema_nodes_.size()); |
+ schema_nodes_.push_back(SchemaNode()); |
+ SchemaNode& node = schema_nodes_.back(); |
+ node.type = type; |
+ node.extra = kInvalid; |
+ return index; |
} |
-const internal::SchemaNode* SchemaOwner::ParseDictionary( |
+// static |
+int SchemaOwner::InternalStorage::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); |
+ // 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 schema_index = static_cast<int>(schema_nodes_.size()); |
+ schema_nodes_.push_back(SchemaNode()); |
+ |
+ int extra = static_cast<int>(properties_nodes_.size()); |
+ properties_nodes_.push_back(PropertiesNode()); |
+ properties_nodes_[extra].begin = kInvalid; |
+ properties_nodes_[extra].end = kInvalid; |
+ properties_nodes_[extra].additional = kInvalid; |
const base::DictionaryValue* dict = NULL; |
+ if (schema.GetDictionary(json_schema_constants::kAdditionalProperties, |
+ &dict)) { |
+ int additional = Parse(*dict, error); |
+ if (additional == kInvalid) |
+ return kInvalid; |
+ properties_nodes_[extra].additional = additional; |
+ } |
+ |
const base::DictionaryValue* properties = NULL; |
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>(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. |
+ property_nodes_.resize(base_index + properties->size()); |
- size_t index = 0; |
+ int index = base_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); |
+ if (extra == kInvalid) |
+ return kInvalid; |
+ strings_.push_back(new std::string(it.key())); |
+ property_nodes_[index].key = strings_.back()->c_str(); |
+ 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); |
+ properties_nodes_[extra].begin = base_index; |
+ 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; |
+ schema_nodes_[schema_index].type = base::Value::TYPE_DICTIONARY; |
+ schema_nodes_[schema_index].extra = extra; |
+ return schema_index; |
} |
-const internal::SchemaNode* SchemaOwner::ParseList( |
- const base::DictionaryValue& schema, |
- std::string* error) { |
+// static |
+int SchemaOwner::InternalStorage::ParseList(const base::DictionaryValue& schema, |
+ std::string* error) { |
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); |
+ if (extra == kInvalid) |
+ return kInvalid; |
+ int index = static_cast<int>(schema_nodes_.size()); |
+ schema_nodes_.push_back(SchemaNode()); |
+ schema_nodes_[index].type = base::Value::TYPE_LIST; |
+ schema_nodes_[index].extra = extra; |
+ return index; |
} |
} // namespace policy |