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; |
} |
} |