| Index: base/values.cc
|
| diff --git a/base/values.cc b/base/values.cc
|
| index ca3692deccae32ff401b99ac35487db78dc66199..82b137a2826d101e17c80d51da81e91508814a1b 100644
|
| --- a/base/values.cc
|
| +++ b/base/values.cc
|
| @@ -73,16 +73,95 @@ std::unique_ptr<Value> CopyWithoutEmptyChildren(const Value& node) {
|
| }
|
| }
|
|
|
| -} // namespace
|
| +// TODO(crbug.com/646113): Remove this once all types are implemented.
|
| +bool IsAssignmentSafe(Value::Type lhs, Value::Type rhs) {
|
| + auto IsImplemented = [](Value::Type type) {
|
| + return type == Value::Type::NONE || type == Value::Type::BOOLEAN ||
|
| + type == Value::Type::INTEGER || type == Value::Type::DOUBLE;
|
| + };
|
|
|
| -Value::~Value() {
|
| + return lhs == rhs || (IsImplemented(lhs) && IsImplemented(rhs));
|
| }
|
|
|
| +} // namespace
|
| +
|
| // static
|
| std::unique_ptr<Value> Value::CreateNullValue() {
|
| return WrapUnique(new Value(Type::NONE));
|
| }
|
|
|
| +Value::Value(const Value& that) {
|
| + InternalCopyFrom(that);
|
| +}
|
| +
|
| +Value::Value(Value&& that) {
|
| + // TODO(crbug.com/646113): Implement InternalMoveFrom for types where moving
|
| + // and copying differ.
|
| + InternalCopyFrom(that);
|
| +}
|
| +
|
| +Value::Value() : type_(Type::NONE) {}
|
| +
|
| +Value::Value(Type type) : type_(type) {
|
| + // Initialize with the default value.
|
| + switch (type_) {
|
| + case Type::NONE:
|
| + return;
|
| +
|
| + case Type::BOOLEAN:
|
| + bool_value_ = false;
|
| + return;
|
| + case Type::INTEGER:
|
| + int_value_ = 0;
|
| + return;
|
| + case Type::DOUBLE:
|
| + double_value_ = 0.0;
|
| + return;
|
| +
|
| + // TODO(crbug.com/646113): Implement these once the corresponding derived
|
| + // classes are removed.
|
| + case Type::STRING:
|
| + case Type::BINARY:
|
| + case Type::LIST:
|
| + case Type::DICTIONARY:
|
| + return;
|
| + }
|
| +}
|
| +
|
| +Value::Value(bool in_bool) : type_(Type::BOOLEAN), bool_value_(in_bool) {}
|
| +
|
| +Value::Value(int in_int) : type_(Type::INTEGER), int_value_(in_int) {}
|
| +
|
| +Value::Value(double in_double) : type_(Type::DOUBLE), double_value_(in_double) {
|
| + if (!std::isfinite(double_value_)) {
|
| + NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) "
|
| + << "values cannot be represented in JSON";
|
| + double_value_ = 0.0;
|
| + }
|
| +}
|
| +
|
| +Value& Value::operator=(const Value& that) {
|
| + if (this != &that) {
|
| + DCHECK(IsAssignmentSafe(type_, that.type_));
|
| + InternalCopyFrom(that);
|
| + }
|
| +
|
| + return *this;
|
| +}
|
| +
|
| +Value& Value::operator=(Value&& that) {
|
| + if (this != &that) {
|
| + // TODO(crbug.com/646113): Implement InternalMoveFrom for types where moving
|
| + // and copying differ.
|
| + DCHECK(IsAssignmentSafe(type_, that.type_));
|
| + InternalCopyFrom(that);
|
| + }
|
| +
|
| + return *this;
|
| +}
|
| +
|
| +Value::~Value() {}
|
| +
|
| // static
|
| const char* Value::GetTypeName(Value::Type type) {
|
| DCHECK_GE(static_cast<int>(type), 0);
|
| @@ -90,20 +169,51 @@ const char* Value::GetTypeName(Value::Type type) {
|
| return kTypeNames[static_cast<size_t>(type)];
|
| }
|
|
|
| -bool Value::GetAsBinary(const BinaryValue** out_value) const {
|
| - return false;
|
| +bool Value::GetBool() const {
|
| + CHECK(is_bool());
|
| + return bool_value_;
|
| +}
|
| +
|
| +int Value::GetInt() const {
|
| + CHECK(is_int());
|
| + return int_value_;
|
| +}
|
| +
|
| +double Value::GetDouble() const {
|
| + if (is_double())
|
| + return double_value_;
|
| + if (is_int())
|
| + return int_value_;
|
| + CHECK(false);
|
| + return 0.0;
|
| }
|
|
|
| bool Value::GetAsBoolean(bool* out_value) const {
|
| - return false;
|
| + if (out_value && is_bool()) {
|
| + *out_value = bool_value_;
|
| + return true;
|
| + }
|
| + return is_bool();
|
| }
|
|
|
| bool Value::GetAsInteger(int* out_value) const {
|
| - return false;
|
| + if (out_value && is_int()) {
|
| + *out_value = int_value_;
|
| + return true;
|
| + }
|
| + return is_int();
|
| }
|
|
|
| bool Value::GetAsDouble(double* out_value) const {
|
| - return false;
|
| + if (out_value && is_double()) {
|
| + *out_value = double_value_;
|
| + return true;
|
| + } else if (out_value && is_int()) {
|
| + // Allow promotion from int to double.
|
| + *out_value = int_value_;
|
| + return true;
|
| + }
|
| + return is_double() || is_int();
|
| }
|
|
|
| bool Value::GetAsString(std::string* out_value) const {
|
| @@ -122,6 +232,10 @@ bool Value::GetAsString(StringPiece* out_value) const {
|
| return false;
|
| }
|
|
|
| +bool Value::GetAsBinary(const BinaryValue** out_value) const {
|
| + return false;
|
| +}
|
| +
|
| bool Value::GetAsList(ListValue** out_value) {
|
| return false;
|
| }
|
| @@ -141,8 +255,24 @@ bool Value::GetAsDictionary(const DictionaryValue** out_value) const {
|
| Value* Value::DeepCopy() const {
|
| // This method should only be getting called for null Values--all subclasses
|
| // need to provide their own implementation;.
|
| - DCHECK(IsType(Type::NONE));
|
| - return CreateNullValue().release();
|
| + switch (type()) {
|
| + case Type::NONE:
|
| + return CreateNullValue().release();
|
| +
|
| + // For now, make FundamentalValues for backward-compatibility. Convert to
|
| + // Value when that code is deleted.
|
| + case Type::BOOLEAN:
|
| + return new FundamentalValue(bool_value_);
|
| + case Type::INTEGER:
|
| + return new FundamentalValue(int_value_);
|
| + case Type::DOUBLE:
|
| + return new FundamentalValue(double_value_);
|
| +
|
| + default:
|
| + // All other types should be handled by subclasses.
|
| + NOTREACHED();
|
| + return nullptr;
|
| + }
|
| }
|
|
|
| std::unique_ptr<Value> Value::CreateDeepCopy() const {
|
| @@ -150,10 +280,24 @@ std::unique_ptr<Value> Value::CreateDeepCopy() const {
|
| }
|
|
|
| bool Value::Equals(const Value* other) const {
|
| - // This method should only be getting called for null Values--all subclasses
|
| - // need to provide their own implementation;.
|
| - DCHECK(IsType(Type::NONE));
|
| - return other->IsType(Type::NONE);
|
| + if (other->type() != type())
|
| + return false;
|
| +
|
| + switch (type()) {
|
| + case Type::NONE:
|
| + return true;
|
| + case Type::BOOLEAN:
|
| + return bool_value_ == other->bool_value_;
|
| + case Type::INTEGER:
|
| + return int_value_ == other->int_value_;
|
| + case Type::DOUBLE:
|
| + return double_value_ == other->double_value_;
|
| + default:
|
| + // This method should only be getting called for the above types -- all
|
| + // subclasses need to provide their own implementation;.
|
| + NOTREACHED();
|
| + return false;
|
| + }
|
| }
|
|
|
| // static
|
| @@ -163,92 +307,30 @@ bool Value::Equals(const Value* a, const Value* b) {
|
| return a->Equals(b);
|
| }
|
|
|
| -Value::Value(Type type) : type_(type) {}
|
| -
|
| -Value::Value(const Value& that) : type_(that.type_) {}
|
| -
|
| -Value& Value::operator=(const Value& that) {
|
| +void Value::InternalCopyFrom(const Value& that) {
|
| type_ = that.type_;
|
| - return *this;
|
| -}
|
| -
|
| -///////////////////// FundamentalValue ////////////////////
|
| -
|
| -FundamentalValue::FundamentalValue(bool in_value)
|
| - : Value(Type::BOOLEAN), boolean_value_(in_value) {}
|
| -
|
| -FundamentalValue::FundamentalValue(int in_value)
|
| - : Value(Type::INTEGER), integer_value_(in_value) {}
|
| -
|
| -FundamentalValue::FundamentalValue(double in_value)
|
| - : Value(Type::DOUBLE), double_value_(in_value) {
|
| - if (!std::isfinite(double_value_)) {
|
| - NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) "
|
| - << "values cannot be represented in JSON";
|
| - double_value_ = 0.0;
|
| - }
|
| -}
|
| -
|
| -FundamentalValue::~FundamentalValue() {
|
| -}
|
| -
|
| -bool FundamentalValue::GetAsBoolean(bool* out_value) const {
|
| - if (out_value && IsType(Type::BOOLEAN))
|
| - *out_value = boolean_value_;
|
| - return (IsType(Type::BOOLEAN));
|
| -}
|
| -
|
| -bool FundamentalValue::GetAsInteger(int* out_value) const {
|
| - if (out_value && IsType(Type::INTEGER))
|
| - *out_value = integer_value_;
|
| - return (IsType(Type::INTEGER));
|
| -}
|
| + switch (type_) {
|
| + case Type::NONE:
|
| + // Nothing to do.
|
| + return;
|
|
|
| -bool FundamentalValue::GetAsDouble(double* out_value) const {
|
| - if (out_value && IsType(Type::DOUBLE))
|
| - *out_value = double_value_;
|
| - else if (out_value && IsType(Type::INTEGER))
|
| - *out_value = integer_value_;
|
| - return (IsType(Type::DOUBLE) || IsType(Type::INTEGER));
|
| -}
|
| -
|
| -FundamentalValue* FundamentalValue::DeepCopy() const {
|
| - switch (GetType()) {
|
| case Type::BOOLEAN:
|
| - return new FundamentalValue(boolean_value_);
|
| -
|
| + bool_value_ = that.bool_value_;
|
| + return;
|
| case Type::INTEGER:
|
| - return new FundamentalValue(integer_value_);
|
| -
|
| + int_value_ = that.int_value_;
|
| + return;
|
| case Type::DOUBLE:
|
| - return new FundamentalValue(double_value_);
|
| -
|
| - default:
|
| - NOTREACHED();
|
| - return NULL;
|
| - }
|
| -}
|
| -
|
| -bool FundamentalValue::Equals(const Value* other) const {
|
| - if (other->GetType() != GetType())
|
| - return false;
|
| -
|
| - switch (GetType()) {
|
| - case Type::BOOLEAN: {
|
| - bool lhs, rhs;
|
| - return GetAsBoolean(&lhs) && other->GetAsBoolean(&rhs) && lhs == rhs;
|
| - }
|
| - case Type::INTEGER: {
|
| - int lhs, rhs;
|
| - return GetAsInteger(&lhs) && other->GetAsInteger(&rhs) && lhs == rhs;
|
| - }
|
| - case Type::DOUBLE: {
|
| - double lhs, rhs;
|
| - return GetAsDouble(&lhs) && other->GetAsDouble(&rhs) && lhs == rhs;
|
| - }
|
| - default:
|
| - NOTREACHED();
|
| - return false;
|
| + double_value_ = that.double_value_;
|
| + return;
|
| +
|
| + // TODO(crbug.com/646113): Implement these once the corresponding derived
|
| + // classes are removed.
|
| + case Type::STRING:
|
| + case Type::BINARY:
|
| + case Type::LIST:
|
| + case Type::DICTIONARY:
|
| + return;
|
| }
|
| }
|
|
|
|
|