Commit 79d02214 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Commit Bot

[base] Use absl::variant in base::Value

This change makes use of absl::variant inside of base::Value and
replaces the manually written tagged union.

Since adding an Abseil #include requires propagation of the
corresponding absl_include_config, several deps have been changed to
public_deps in order to avoid build errors.

TBR=battre

Bug: 646113
Change-Id: I781fb43aa0eb4caacbda7f745babd042755f199c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2332182
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarChristian Dullweber <dullweber@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarVarun Khaneja <vakh@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799725}
parent ecaecf31
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/tracing_buildflags.h" #include "base/tracing_buildflags.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
#if BUILDFLAG(ENABLE_BASE_TRACING) #if BUILDFLAG(ENABLE_BASE_TRACING)
#include "base/trace_event/memory_usage_estimator.h" // no-presubmit-check #include "base/trace_event/memory_usage_estimator.h" // no-presubmit-check
...@@ -29,23 +30,6 @@ ...@@ -29,23 +30,6 @@
namespace base { namespace base {
// base::Value must be standard layout to guarantee that writing to
// |bool_type_| then reading |type_| is defined behaviour. See:
//
// [class.union]:
// If a standard-layout union contains several standard-layout structs that
// share a common initial sequence (9.2), and if an object of this
// standard-layout union type contains one of the standard-layout structs,
// it is permitted to inspect the common initial sequence of any of
// standard-layout struct members;
//
static_assert(std::is_standard_layout<Value>::value,
"base::Value should be a standard-layout C++ class in order "
"to avoid undefined behaviour in its implementation!");
static_assert(sizeof(Value::DoubleStorage) == sizeof(double),
"The double and DoubleStorage types should have the same size");
namespace { namespace {
const char* const kTypeNames[] = {"null", "boolean", "integer", "double", const char* const kTypeNames[] = {"null", "boolean", "integer", "double",
...@@ -165,36 +149,36 @@ const ListValue& Value::AsListValue(const Value& val) { ...@@ -165,36 +149,36 @@ const ListValue& Value::AsListValue(const Value& val) {
return static_cast<const ListValue&>(val); return static_cast<const ListValue&>(val);
} }
Value::Value(Value&& that) noexcept { Value::Value() noexcept = default;
InternalMoveConstructFrom(std::move(that));
} Value::Value(Value&& that) noexcept = default;
Value::Value(Type type) : type_(type) { Value::Value(Type type) {
// Initialize with the default value. // Initialize with the default value.
switch (type_) { switch (type) {
case Type::NONE: case Type::NONE:
return; return;
case Type::BOOLEAN: case Type::BOOLEAN:
bool_value_ = false; data_.emplace<bool>(false);
return; return;
case Type::INTEGER: case Type::INTEGER:
int_value_ = 0; data_.emplace<int>(0);
return; return;
case Type::DOUBLE: case Type::DOUBLE:
double_value_ = bit_cast<DoubleStorage>(0.0); data_.emplace<DoubleStorage>(bit_cast<DoubleStorage>(0.0));
return; return;
case Type::STRING: case Type::STRING:
new (&string_value_) std::string(); data_.emplace<std::string>();
return; return;
case Type::BINARY: case Type::BINARY:
new (&binary_value_) BlobStorage(); data_.emplace<BlobStorage>();
return; return;
case Type::DICTIONARY: case Type::DICTIONARY:
new (&dict_) DictStorage(); data_.emplace<DictStorage>();
return; return;
case Type::LIST: case Type::LIST:
new (&list_) ListStorage(); data_.emplace<ListStorage>();
return; return;
// TODO(crbug.com/859477): Remove after root cause is found. // TODO(crbug.com/859477): Remove after root cause is found.
case Type::DEAD: case Type::DEAD:
...@@ -206,16 +190,15 @@ Value::Value(Type type) : type_(type) { ...@@ -206,16 +190,15 @@ Value::Value(Type type) : type_(type) {
CHECK(false); CHECK(false);
} }
Value::Value(bool in_bool) : type_(Type::BOOLEAN), bool_value_(in_bool) {} Value::Value(bool in_bool) : data_(in_bool) {}
Value::Value(int in_int) : type_(Type::INTEGER), int_value_(in_int) {} Value::Value(int in_int) : data_(in_int) {}
Value::Value(double in_double) Value::Value(double in_double) : data_(bit_cast<DoubleStorage>(in_double)) {
: type_(Type::DOUBLE), double_value_(bit_cast<DoubleStorage>(in_double)) {
if (!std::isfinite(in_double)) { if (!std::isfinite(in_double)) {
NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) " NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) "
<< "values cannot be represented in JSON"; << "values cannot be represented in JSON";
double_value_ = bit_cast<DoubleStorage>(0.0); data_ = bit_cast<DoubleStorage>(0.0);
} }
} }
...@@ -223,9 +206,8 @@ Value::Value(const char* in_string) : Value(std::string(in_string)) {} ...@@ -223,9 +206,8 @@ Value::Value(const char* in_string) : Value(std::string(in_string)) {}
Value::Value(StringPiece in_string) : Value(std::string(in_string)) {} Value::Value(StringPiece in_string) : Value(std::string(in_string)) {}
Value::Value(std::string&& in_string) noexcept Value::Value(std::string&& in_string) noexcept : data_(std::move(in_string)) {
: type_(Type::STRING), string_value_(std::move(in_string)) { DCHECK(IsStringUTF8AllowingNoncharacters(GetString()));
DCHECK(IsStringUTF8AllowingNoncharacters(string_value_));
} }
Value::Value(const char16* in_string16) : Value(StringPiece16(in_string16)) {} Value::Value(const char16* in_string16) : Value(StringPiece16(in_string16)) {}
...@@ -233,79 +215,51 @@ Value::Value(const char16* in_string16) : Value(StringPiece16(in_string16)) {} ...@@ -233,79 +215,51 @@ Value::Value(const char16* in_string16) : Value(StringPiece16(in_string16)) {}
Value::Value(StringPiece16 in_string16) : Value(UTF16ToUTF8(in_string16)) {} Value::Value(StringPiece16 in_string16) : Value(UTF16ToUTF8(in_string16)) {}
Value::Value(const std::vector<char>& in_blob) Value::Value(const std::vector<char>& in_blob)
: type_(Type::BINARY), binary_value_(in_blob.begin(), in_blob.end()) {} : data_(absl::in_place_type_t<BlobStorage>(),
in_blob.begin(),
in_blob.end()) {}
Value::Value(base::span<const uint8_t> in_blob) Value::Value(base::span<const uint8_t> in_blob)
: type_(Type::BINARY), binary_value_(in_blob.begin(), in_blob.end()) {} : data_(absl::in_place_type_t<BlobStorage>(),
in_blob.begin(),
in_blob.end()) {}
Value::Value(BlobStorage&& in_blob) noexcept Value::Value(BlobStorage&& in_blob) noexcept : data_(std::move(in_blob)) {}
: type_(Type::BINARY), binary_value_(std::move(in_blob)) {}
Value::Value(const DictStorage& in_dict) : type_(Type::DICTIONARY), dict_() { Value::Value(const DictStorage& in_dict)
dict_.reserve(in_dict.size()); : data_(absl::in_place_type_t<DictStorage>()) {
for (const auto& it : in_dict) { for (const auto& it : in_dict) {
dict_.try_emplace(dict_.end(), it.first, dict().try_emplace(dict().end(), it.first,
std::make_unique<Value>(it.second->Clone())); std::make_unique<Value>(it.second->Clone()));
} }
} }
Value::Value(DictStorage&& in_dict) noexcept Value::Value(DictStorage&& in_dict) noexcept : data_(std::move(in_dict)) {}
: type_(Type::DICTIONARY), dict_(std::move(in_dict)) {}
Value::Value(span<const Value> in_list) : type_(Type::LIST), list_() { Value::Value(span<const Value> in_list)
list_.reserve(in_list.size()); : data_(absl::in_place_type_t<ListStorage>()) {
list().reserve(in_list.size());
for (const auto& val : in_list) for (const auto& val : in_list)
list_.emplace_back(val.Clone()); list().emplace_back(val.Clone());
} }
Value::Value(ListStorage&& in_list) noexcept Value::Value(ListStorage&& in_list) noexcept : data_(std::move(in_list)) {}
: type_(Type::LIST), list_(std::move(in_list)) {}
Value& Value::operator=(Value&& that) noexcept { Value& Value::operator=(Value&& that) noexcept = default;
InternalCleanup();
InternalMoveConstructFrom(std::move(that));
return *this; Value::Value(absl::monostate) {}
}
Value::Value(DoubleStorage storage) : data_(std::move(storage)) {}
double Value::AsDoubleInternal() const { double Value::AsDoubleInternal() const {
return bit_cast<double>(double_value_); return bit_cast<double>(absl::get<DoubleStorage>(data_));
} }
Value Value::Clone() const { Value Value::Clone() const {
switch (type_) { return absl::visit([](const auto& member) { return Value(member); }, data_);
case Type::NONE:
return Value();
case Type::BOOLEAN:
return Value(bool_value_);
case Type::INTEGER:
return Value(int_value_);
case Type::DOUBLE:
return Value(AsDoubleInternal());
case Type::STRING:
return Value(string_value_);
case Type::BINARY:
return Value(binary_value_);
case Type::DICTIONARY:
return Value(dict_);
case Type::LIST:
return Value(list_);
// TODO(crbug.com/859477): Remove after root cause is found.
case Type::DEAD:
CHECK(false);
return Value();
}
// TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
CHECK(false);
return Value();
} }
Value::~Value() { Value::~Value() = default;
InternalCleanup();
// TODO(crbug.com/859477): Remove after root cause is found.
type_ = Type::DEAD;
}
// static // static
const char* Value::GetTypeName(Value::Type type) { const char* Value::GetTypeName(Value::Type type) {
...@@ -315,116 +269,97 @@ const char* Value::GetTypeName(Value::Type type) { ...@@ -315,116 +269,97 @@ const char* Value::GetTypeName(Value::Type type) {
} }
bool Value::GetBool() const { bool Value::GetBool() const {
CHECK(is_bool()); return absl::get<bool>(data_);
return bool_value_;
} }
int Value::GetInt() const { int Value::GetInt() const {
CHECK(is_int()); return absl::get<int>(data_);
return int_value_;
} }
double Value::GetDouble() const { double Value::GetDouble() const {
if (is_double()) if (is_double())
return AsDoubleInternal(); return AsDoubleInternal();
if (is_int()) if (is_int())
return int_value_; return GetInt();
CHECK(false); CHECK(false);
return 0.0; return 0.0;
} }
const std::string& Value::GetString() const { const std::string& Value::GetString() const {
CHECK(is_string()); return absl::get<std::string>(data_);
return string_value_;
} }
std::string& Value::GetString() { std::string& Value::GetString() {
CHECK(is_string()); return absl::get<std::string>(data_);
return string_value_;
} }
const Value::BlobStorage& Value::GetBlob() const { const Value::BlobStorage& Value::GetBlob() const {
CHECK(is_blob()); return absl::get<BlobStorage>(data_);
return binary_value_;
} }
Value::ListView Value::GetList() { Value::ListView Value::GetList() {
CHECK(is_list()); return list();
return list_;
} }
Value::ConstListView Value::GetList() const { Value::ConstListView Value::GetList() const {
CHECK(is_list()); return list();
return list_;
} }
Value::ListStorage Value::TakeList() { Value::ListStorage Value::TakeList() {
CHECK(is_list()); return std::exchange(list(), {});
return std::exchange(list_, ListStorage());
} }
void Value::Append(bool value) { void Value::Append(bool value) {
CHECK(is_list()); list().emplace_back(value);
list_.emplace_back(value);
} }
void Value::Append(int value) { void Value::Append(int value) {
CHECK(is_list()); list().emplace_back(value);
list_.emplace_back(value);
} }
void Value::Append(double value) { void Value::Append(double value) {
CHECK(is_list()); list().emplace_back(value);
list_.emplace_back(value);
} }
void Value::Append(const char* value) { void Value::Append(const char* value) {
CHECK(is_list()); list().emplace_back(value);
list_.emplace_back(value);
} }
void Value::Append(StringPiece value) { void Value::Append(StringPiece value) {
CHECK(is_list()); list().emplace_back(value);
list_.emplace_back(value);
} }
void Value::Append(std::string&& value) { void Value::Append(std::string&& value) {
CHECK(is_list()); list().emplace_back(std::move(value));
list_.emplace_back(std::move(value));
} }
void Value::Append(const char16* value) { void Value::Append(const char16* value) {
CHECK(is_list()); list().emplace_back(value);
list_.emplace_back(value);
} }
void Value::Append(StringPiece16 value) { void Value::Append(StringPiece16 value) {
CHECK(is_list()); list().emplace_back(value);
list_.emplace_back(value);
} }
void Value::Append(Value&& value) { void Value::Append(Value&& value) {
CHECK(is_list()); list().emplace_back(std::move(value));
list_.emplace_back(std::move(value));
} }
CheckedContiguousIterator<Value> Value::Insert( CheckedContiguousIterator<Value> Value::Insert(
CheckedContiguousConstIterator<Value> pos, CheckedContiguousConstIterator<Value> pos,
Value&& value) { Value&& value) {
CHECK(is_list()); const auto offset = pos - make_span(list()).begin();
const auto offset = pos - make_span(list_).begin(); list().insert(list().begin() + offset, std::move(value));
list_.insert(list_.begin() + offset, std::move(value)); return make_span(list()).begin() + offset;
return make_span(list_).begin() + offset;
} }
bool Value::EraseListIter(CheckedContiguousConstIterator<Value> iter) { bool Value::EraseListIter(CheckedContiguousConstIterator<Value> iter) {
CHECK(is_list()); const auto offset = iter - ListView(list()).begin();
const auto offset = iter - ListView(list_).begin(); auto list_iter = list().begin() + offset;
auto list_iter = list_.begin() + offset; if (list_iter == list().end())
if (list_iter == list_.end())
return false; return false;
list_.erase(list_iter); list().erase(list_iter);
return true; return true;
} }
...@@ -433,8 +368,7 @@ size_t Value::EraseListValue(const Value& val) { ...@@ -433,8 +368,7 @@ size_t Value::EraseListValue(const Value& val) {
} }
void Value::ClearList() { void Value::ClearList() {
CHECK(is_list()); list().clear();
list_.clear();
} }
Value* Value::FindKey(StringPiece key) { Value* Value::FindKey(StringPiece key) {
...@@ -442,9 +376,8 @@ Value* Value::FindKey(StringPiece key) { ...@@ -442,9 +376,8 @@ Value* Value::FindKey(StringPiece key) {
} }
const Value* Value::FindKey(StringPiece key) const { const Value* Value::FindKey(StringPiece key) const {
CHECK(is_dict()); auto found = dict().find(key);
auto found = dict_.find(key); if (found == dict().end())
if (found == dict_.end())
return nullptr; return nullptr;
return found->second.get(); return found->second.get();
} }
...@@ -462,39 +395,35 @@ const Value* Value::FindKeyOfType(StringPiece key, Type type) const { ...@@ -462,39 +395,35 @@ const Value* Value::FindKeyOfType(StringPiece key, Type type) const {
base::Optional<bool> Value::FindBoolKey(StringPiece key) const { base::Optional<bool> Value::FindBoolKey(StringPiece key) const {
const Value* result = FindKeyOfType(key, Type::BOOLEAN); const Value* result = FindKeyOfType(key, Type::BOOLEAN);
return result ? base::make_optional(result->bool_value_) : base::nullopt; return result ? base::make_optional(result->GetBool()) : base::nullopt;
} }
base::Optional<int> Value::FindIntKey(StringPiece key) const { base::Optional<int> Value::FindIntKey(StringPiece key) const {
const Value* result = FindKeyOfType(key, Type::INTEGER); const Value* result = FindKeyOfType(key, Type::INTEGER);
return result ? base::make_optional(result->int_value_) : base::nullopt; return result ? base::make_optional(result->GetInt()) : base::nullopt;
} }
base::Optional<double> Value::FindDoubleKey(StringPiece key) const { base::Optional<double> Value::FindDoubleKey(StringPiece key) const {
const Value* result = FindKey(key); if (const Value* cur = FindKey(key)) {
if (result) { if (cur->is_int() || cur->is_double())
if (result->is_int()) return cur->GetDouble();
return static_cast<double>(result->int_value_);
if (result->is_double()) {
return result->AsDoubleInternal();
}
} }
return base::nullopt; return base::nullopt;
} }
const std::string* Value::FindStringKey(StringPiece key) const { const std::string* Value::FindStringKey(StringPiece key) const {
const Value* result = FindKeyOfType(key, Type::STRING); const Value* result = FindKey(key);
return result ? &result->string_value_ : nullptr; return result ? absl::get_if<std::string>(&result->data_) : nullptr;
} }
std::string* Value::FindStringKey(StringPiece key) { std::string* Value::FindStringKey(StringPiece key) {
Value* result = FindKeyOfType(key, Type::STRING); return const_cast<std::string*>(as_const(*this).FindStringKey(key));
return result ? &result->string_value_ : nullptr;
} }
const Value::BlobStorage* Value::FindBlobKey(StringPiece key) const { const Value::BlobStorage* Value::FindBlobKey(StringPiece key) const {
const Value* value = FindKeyOfType(key, Type::BINARY); const Value* result = FindKey(key);
return value ? &value->binary_value_ : nullptr; return result ? absl::get_if<BlobStorage>(&result->data_) : nullptr;
} }
const Value* Value::FindDictKey(StringPiece key) const { const Value* Value::FindDictKey(StringPiece key) const {
...@@ -518,8 +447,7 @@ Value* Value::SetKey(StringPiece key, Value&& value) { ...@@ -518,8 +447,7 @@ Value* Value::SetKey(StringPiece key, Value&& value) {
} }
Value* Value::SetKey(std::string&& key, Value&& value) { Value* Value::SetKey(std::string&& key, Value&& value) {
CHECK(is_dict()); return dict()
return dict_
.insert_or_assign(std::move(key), .insert_or_assign(std::move(key),
std::make_unique<Value>(std::move(value))) std::make_unique<Value>(std::move(value)))
.first->second.get(); .first->second.get();
...@@ -558,18 +486,16 @@ Value* Value::SetStringKey(StringPiece key, std::string&& value) { ...@@ -558,18 +486,16 @@ Value* Value::SetStringKey(StringPiece key, std::string&& value) {
} }
bool Value::RemoveKey(StringPiece key) { bool Value::RemoveKey(StringPiece key) {
CHECK(is_dict()); return dict().erase(key) != 0;
return dict_.erase(key) != 0;
} }
Optional<Value> Value::ExtractKey(StringPiece key) { Optional<Value> Value::ExtractKey(StringPiece key) {
CHECK(is_dict()); auto found = dict().find(key);
auto found = dict_.find(key); if (found == dict().end())
if (found == dict_.end())
return nullopt; return nullopt;
Value value = std::move(*found->second); Value value = std::move(*found->second);
dict_.erase(found); dict().erase(found);
return std::move(value); return std::move(value);
} }
...@@ -603,32 +529,28 @@ base::Optional<bool> Value::FindBoolPath(StringPiece path) const { ...@@ -603,32 +529,28 @@ base::Optional<bool> Value::FindBoolPath(StringPiece path) const {
const Value* cur = FindPath(path); const Value* cur = FindPath(path);
if (!cur || !cur->is_bool()) if (!cur || !cur->is_bool())
return base::nullopt; return base::nullopt;
return cur->bool_value_; return cur->GetBool();
} }
base::Optional<int> Value::FindIntPath(StringPiece path) const { base::Optional<int> Value::FindIntPath(StringPiece path) const {
const Value* cur = FindPath(path); const Value* cur = FindPath(path);
if (!cur || !cur->is_int()) if (!cur || !cur->is_int())
return base::nullopt; return base::nullopt;
return cur->int_value_; return cur->GetInt();
} }
base::Optional<double> Value::FindDoublePath(StringPiece path) const { base::Optional<double> Value::FindDoublePath(StringPiece path) const {
const Value* cur = FindPath(path); if (const Value* cur = FindPath(path)) {
if (cur) { if (cur->is_int() || cur->is_double())
if (cur->is_int()) return cur->GetDouble();
return static_cast<double>(cur->int_value_);
if (cur->is_double())
return cur->AsDoubleInternal();
} }
return base::nullopt; return base::nullopt;
} }
const std::string* Value::FindStringPath(StringPiece path) const { const std::string* Value::FindStringPath(StringPiece path) const {
const Value* cur = FindPath(path); const Value* result = FindPath(path);
if (!cur || !cur->is_string()) return result ? absl::get_if<std::string>(&result->data_) : nullptr;
return nullptr;
return &cur->string_value_;
} }
std::string* Value::FindStringPath(StringPiece path) { std::string* Value::FindStringPath(StringPiece path) {
...@@ -636,10 +558,8 @@ std::string* Value::FindStringPath(StringPiece path) { ...@@ -636,10 +558,8 @@ std::string* Value::FindStringPath(StringPiece path) {
} }
const Value::BlobStorage* Value::FindBlobPath(StringPiece path) const { const Value::BlobStorage* Value::FindBlobPath(StringPiece path) const {
const Value* cur = FindPath(path); const Value* result = FindPath(path);
if (!cur || !cur->is_blob()) return result ? absl::get_if<BlobStorage>(&result->data_) : nullptr;
return nullptr;
return &cur->binary_value_;
} }
const Value* Value::FindDictPath(StringPiece path) const { const Value* Value::FindDictPath(StringPiece path) const {
...@@ -705,13 +625,13 @@ Optional<Value> Value::ExtractPath(StringPiece path) { ...@@ -705,13 +625,13 @@ Optional<Value> Value::ExtractPath(StringPiece path) {
if (pos == path.npos) if (pos == path.npos)
return ExtractKey(path); return ExtractKey(path);
auto found = dict_.find(path.substr(0, pos)); auto found = dict().find(path.substr(0, pos));
if (found == dict_.end() || !found->second->is_dict()) if (found == dict().end() || !found->second->is_dict())
return nullopt; return nullopt;
Optional<Value> extracted = found->second->ExtractPath(path.substr(pos + 1)); Optional<Value> extracted = found->second->ExtractPath(path.substr(pos + 1));
if (extracted && found->second->dict_.empty()) if (extracted && found->second->dict().empty())
dict_.erase(found); dict().erase(found);
return extracted; return extracted;
} }
...@@ -780,10 +700,10 @@ Value* Value::SetPath(span<const StringPiece> path, Value&& value) { ...@@ -780,10 +700,10 @@ Value* Value::SetPath(span<const StringPiece> path, Value&& value) {
// Use lower_bound to avoid doing the search twice for missing keys. // Use lower_bound to avoid doing the search twice for missing keys.
const StringPiece path_component = *cur_path; const StringPiece path_component = *cur_path;
auto found = cur->dict_.lower_bound(path_component); auto found = cur->dict().lower_bound(path_component);
if (found == cur->dict_.end() || found->first != path_component) { if (found == cur->dict().end() || found->first != path_component) {
// No key found, insert one. // No key found, insert one.
auto inserted = cur->dict_.try_emplace( auto inserted = cur->dict().try_emplace(
found, path_component, std::make_unique<Value>(Type::DICTIONARY)); found, path_component, std::make_unique<Value>(Type::DICTIONARY));
cur = inserted->second.get(); cur = inserted->second.get();
} else { } else {
...@@ -809,47 +729,41 @@ bool Value::RemovePath(span<const StringPiece> path) { ...@@ -809,47 +729,41 @@ bool Value::RemovePath(span<const StringPiece> path) {
if (path.size() == 1) if (path.size() == 1)
return RemoveKey(path[0]); return RemoveKey(path[0]);
auto found = dict_.find(path[0]); auto found = dict().find(path[0]);
if (found == dict_.end() || !found->second->is_dict()) if (found == dict().end() || !found->second->is_dict())
return false; return false;
bool removed = found->second->RemovePath(path.subspan(1)); bool removed = found->second->RemovePath(path.subspan(1));
if (removed && found->second->dict_.empty()) if (removed && found->second->dict().empty())
dict_.erase(found); dict().erase(found);
return removed; return removed;
} }
Value::dict_iterator_proxy Value::DictItems() { Value::dict_iterator_proxy Value::DictItems() {
CHECK(is_dict()); return dict_iterator_proxy(&dict());
return dict_iterator_proxy(&dict_);
} }
Value::const_dict_iterator_proxy Value::DictItems() const { Value::const_dict_iterator_proxy Value::DictItems() const {
CHECK(is_dict()); return const_dict_iterator_proxy(&dict());
return const_dict_iterator_proxy(&dict_);
} }
size_t Value::DictSize() const { size_t Value::DictSize() const {
CHECK(is_dict()); return dict().size();
return dict_.size();
} }
bool Value::DictEmpty() const { bool Value::DictEmpty() const {
CHECK(is_dict()); return dict().empty();
return dict_.empty();
} }
void Value::MergeDictionary(const Value* dictionary) { void Value::MergeDictionary(const Value* dictionary) {
CHECK(is_dict()); for (const auto& pair : dictionary->dict()) {
CHECK(dictionary->is_dict());
for (const auto& pair : dictionary->dict_) {
const auto& key = pair.first; const auto& key = pair.first;
const auto& val = pair.second; const auto& val = pair.second;
// Check whether we have to merge dictionaries. // Check whether we have to merge dictionaries.
if (val->is_dict()) { if (val->is_dict()) {
auto found = dict_.find(key); auto found = dict().find(key);
if (found != dict_.end() && found->second->is_dict()) { if (found != dict().end() && found->second->is_dict()) {
found->second->MergeDictionary(val.get()); found->second->MergeDictionary(val.get());
continue; continue;
} }
...@@ -862,7 +776,7 @@ void Value::MergeDictionary(const Value* dictionary) { ...@@ -862,7 +776,7 @@ void Value::MergeDictionary(const Value* dictionary) {
bool Value::GetAsBoolean(bool* out_value) const { bool Value::GetAsBoolean(bool* out_value) const {
if (out_value && is_bool()) { if (out_value && is_bool()) {
*out_value = bool_value_; *out_value = GetBool();
return true; return true;
} }
return is_bool(); return is_bool();
...@@ -870,28 +784,24 @@ bool Value::GetAsBoolean(bool* out_value) const { ...@@ -870,28 +784,24 @@ bool Value::GetAsBoolean(bool* out_value) const {
bool Value::GetAsInteger(int* out_value) const { bool Value::GetAsInteger(int* out_value) const {
if (out_value && is_int()) { if (out_value && is_int()) {
*out_value = int_value_; *out_value = GetInt();
return true; return true;
} }
return is_int(); return is_int();
} }
bool Value::GetAsDouble(double* out_value) const { bool Value::GetAsDouble(double* out_value) const {
if (out_value && is_double()) { if (out_value && (is_double() || is_int())) {
*out_value = AsDoubleInternal(); *out_value = GetDouble();
return true;
}
if (out_value && is_int()) {
// Allow promotion from int to double.
*out_value = int_value_;
return true; return true;
} }
return is_double() || is_int(); return is_double() || is_int();
} }
bool Value::GetAsString(std::string* out_value) const { bool Value::GetAsString(std::string* out_value) const {
if (out_value && is_string()) { if (out_value && is_string()) {
*out_value = string_value_; *out_value = GetString();
return true; return true;
} }
return is_string(); return is_string();
...@@ -899,7 +809,7 @@ bool Value::GetAsString(std::string* out_value) const { ...@@ -899,7 +809,7 @@ bool Value::GetAsString(std::string* out_value) const {
bool Value::GetAsString(string16* out_value) const { bool Value::GetAsString(string16* out_value) const {
if (out_value && is_string()) { if (out_value && is_string()) {
*out_value = UTF8ToUTF16(string_value_); *out_value = UTF8ToUTF16(GetString());
return true; return true;
} }
return is_string(); return is_string();
...@@ -915,7 +825,7 @@ bool Value::GetAsString(const Value** out_value) const { ...@@ -915,7 +825,7 @@ bool Value::GetAsString(const Value** out_value) const {
bool Value::GetAsString(StringPiece* out_value) const { bool Value::GetAsString(StringPiece* out_value) const {
if (out_value && is_string()) { if (out_value && is_string()) {
*out_value = string_value_; *out_value = GetString();
return true; return true;
} }
return is_string(); return is_string();
...@@ -962,35 +872,34 @@ std::unique_ptr<Value> Value::CreateDeepCopy() const { ...@@ -962,35 +872,34 @@ std::unique_ptr<Value> Value::CreateDeepCopy() const {
} }
bool operator==(const Value& lhs, const Value& rhs) { bool operator==(const Value& lhs, const Value& rhs) {
if (lhs.type_ != rhs.type_) if (lhs.type() != rhs.type())
return false; return false;
switch (lhs.type_) { switch (lhs.type()) {
case Value::Type::NONE: case Value::Type::NONE:
return true; return true;
case Value::Type::BOOLEAN: case Value::Type::BOOLEAN:
return lhs.bool_value_ == rhs.bool_value_; return lhs.GetBool() == rhs.GetBool();
case Value::Type::INTEGER: case Value::Type::INTEGER:
return lhs.int_value_ == rhs.int_value_; return lhs.GetInt() == rhs.GetInt();
case Value::Type::DOUBLE: case Value::Type::DOUBLE:
return lhs.AsDoubleInternal() == rhs.AsDoubleInternal(); return lhs.AsDoubleInternal() == rhs.AsDoubleInternal();
case Value::Type::STRING: case Value::Type::STRING:
return lhs.string_value_ == rhs.string_value_; return lhs.GetString() == rhs.GetString();
case Value::Type::BINARY: case Value::Type::BINARY:
return lhs.binary_value_ == rhs.binary_value_; return lhs.GetBlob() == rhs.GetBlob();
// TODO(crbug.com/646113): Clean this up when DictionaryValue and ListValue // TODO(crbug.com/646113): Clean this up when DictionaryValue and ListValue
// are completely inlined. // are completely inlined.
case Value::Type::DICTIONARY: case Value::Type::DICTIONARY:
if (lhs.dict_.size() != rhs.dict_.size()) if (lhs.dict().size() != rhs.dict().size())
return false; return false;
return std::equal(std::begin(lhs.dict_), std::end(lhs.dict_), return std::equal(
std::begin(rhs.dict_), std::begin(lhs.dict()), std::end(lhs.dict()), std::begin(rhs.dict()),
[](const auto& u, const auto& v) { [](const auto& u, const auto& v) {
return std::tie(u.first, *u.second) == return std::tie(u.first, *u.second) == std::tie(v.first, *v.second);
std::tie(v.first, *v.second); });
});
case Value::Type::LIST: case Value::Type::LIST:
return lhs.list_ == rhs.list_; return lhs.list() == rhs.list();
// TODO(crbug.com/859477): Remove after root cause is found. // TODO(crbug.com/859477): Remove after root cause is found.
case Value::Type::DEAD: case Value::Type::DEAD:
CHECK(false); CHECK(false);
...@@ -1007,34 +916,34 @@ bool operator!=(const Value& lhs, const Value& rhs) { ...@@ -1007,34 +916,34 @@ bool operator!=(const Value& lhs, const Value& rhs) {
} }
bool operator<(const Value& lhs, const Value& rhs) { bool operator<(const Value& lhs, const Value& rhs) {
if (lhs.type_ != rhs.type_) if (lhs.type() != rhs.type())
return lhs.type_ < rhs.type_; return lhs.type() < rhs.type();
switch (lhs.type_) { switch (lhs.type()) {
case Value::Type::NONE: case Value::Type::NONE:
return false; return false;
case Value::Type::BOOLEAN: case Value::Type::BOOLEAN:
return lhs.bool_value_ < rhs.bool_value_; return lhs.GetBool() < rhs.GetBool();
case Value::Type::INTEGER: case Value::Type::INTEGER:
return lhs.int_value_ < rhs.int_value_; return lhs.GetInt() < rhs.GetInt();
case Value::Type::DOUBLE: case Value::Type::DOUBLE:
return lhs.AsDoubleInternal() < rhs.AsDoubleInternal(); return lhs.AsDoubleInternal() < rhs.AsDoubleInternal();
case Value::Type::STRING: case Value::Type::STRING:
return lhs.string_value_ < rhs.string_value_; return lhs.GetString() < rhs.GetString();
case Value::Type::BINARY: case Value::Type::BINARY:
return lhs.binary_value_ < rhs.binary_value_; return lhs.GetBlob() < rhs.GetBlob();
// TODO(crbug.com/646113): Clean this up when DictionaryValue and ListValue // TODO(crbug.com/646113): Clean this up when DictionaryValue and ListValue
// are completely inlined. // are completely inlined.
case Value::Type::DICTIONARY: case Value::Type::DICTIONARY:
return std::lexicographical_compare( return std::lexicographical_compare(
std::begin(lhs.dict_), std::end(lhs.dict_), std::begin(rhs.dict_), std::begin(lhs.dict()), std::end(lhs.dict()), std::begin(rhs.dict()),
std::end(rhs.dict_), std::end(rhs.dict()),
[](const Value::DictStorage::value_type& u, [](const Value::DictStorage::value_type& u,
const Value::DictStorage::value_type& v) { const Value::DictStorage::value_type& v) {
return std::tie(u.first, *u.second) < std::tie(v.first, *v.second); return std::tie(u.first, *u.second) < std::tie(v.first, *v.second);
}); });
case Value::Type::LIST: case Value::Type::LIST:
return lhs.list_ < rhs.list_; return lhs.list() < rhs.list();
// TODO(crbug.com/859477): Remove after root cause is found. // TODO(crbug.com/859477): Remove after root cause is found.
case Value::Type::DEAD: case Value::Type::DEAD:
CHECK(false); CHECK(false);
...@@ -1064,96 +973,28 @@ bool Value::Equals(const Value* other) const { ...@@ -1064,96 +973,28 @@ bool Value::Equals(const Value* other) const {
} }
size_t Value::EstimateMemoryUsage() const { size_t Value::EstimateMemoryUsage() const {
switch (type_) { switch (type()) {
#if BUILDFLAG(ENABLE_BASE_TRACING) #if BUILDFLAG(ENABLE_BASE_TRACING)
case Type::STRING: case Type::STRING:
return base::trace_event::EstimateMemoryUsage(string_value_); return base::trace_event::EstimateMemoryUsage(GetString());
case Type::BINARY: case Type::BINARY:
return base::trace_event::EstimateMemoryUsage(binary_value_); return base::trace_event::EstimateMemoryUsage(GetBlob());
case Type::DICTIONARY: case Type::DICTIONARY:
return base::trace_event::EstimateMemoryUsage(dict_); return base::trace_event::EstimateMemoryUsage(dict());
case Type::LIST: case Type::LIST:
return base::trace_event::EstimateMemoryUsage(list_); return base::trace_event::EstimateMemoryUsage(list());
#endif // BUILDFLAG(ENABLE_BASE_TRACING) #endif // BUILDFLAG(ENABLE_BASE_TRACING)
default: default:
return 0; return 0;
} }
} }
void Value::InternalMoveConstructFrom(Value&& that) {
type_ = that.type_;
switch (type_) {
case Type::NONE:
return;
case Type::BOOLEAN:
bool_value_ = that.bool_value_;
return;
case Type::INTEGER:
int_value_ = that.int_value_;
return;
case Type::DOUBLE:
double_value_ = that.double_value_;
return;
case Type::STRING:
new (&string_value_) std::string(std::move(that.string_value_));
return;
case Type::BINARY:
new (&binary_value_) BlobStorage(std::move(that.binary_value_));
return;
case Type::DICTIONARY:
new (&dict_) DictStorage(std::move(that.dict_));
return;
case Type::LIST:
new (&list_) ListStorage(std::move(that.list_));
return;
// TODO(crbug.com/859477): Remove after root cause is found.
case Type::DEAD:
CHECK(false);
return;
}
// TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
CHECK(false);
}
void Value::InternalCleanup() {
switch (type_) {
case Type::NONE:
case Type::BOOLEAN:
case Type::INTEGER:
case Type::DOUBLE:
// Nothing to do
return;
case Type::STRING:
string_value_.~basic_string();
return;
case Type::BINARY:
binary_value_.~BlobStorage();
return;
case Type::DICTIONARY:
dict_.~DictStorage();
return;
case Type::LIST:
list_.~ListStorage();
return;
// TODO(crbug.com/859477): Remove after root cause is found.
case Type::DEAD:
CHECK(false);
return;
}
// TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
CHECK(false);
}
Value* Value::SetKeyInternal(StringPiece key, Value* Value::SetKeyInternal(StringPiece key,
std::unique_ptr<Value>&& val_ptr) { std::unique_ptr<Value>&& val_ptr) {
CHECK(is_dict()); CHECK(is_dict());
// NOTE: We can't use |insert_or_assign| here, as only |try_emplace| does // NOTE: We can't use |insert_or_assign| here, as only |try_emplace| does
// an explicit conversion from StringPiece to std::string if necessary. // an explicit conversion from StringPiece to std::string if necessary.
auto result = dict_.try_emplace(key, std::move(val_ptr)); auto result = dict().try_emplace(key, std::move(val_ptr));
if (!result.second) { if (!result.second) {
// val_ptr is guaranteed to be still intact at this point. // val_ptr is guaranteed to be still intact at this point.
result.first->second = std::move(val_ptr); result.first->second = std::move(val_ptr);
...@@ -1174,10 +1015,10 @@ Value* Value::SetPathInternal(StringPiece path, ...@@ -1174,10 +1015,10 @@ Value* Value::SetPathInternal(StringPiece path,
return nullptr; return nullptr;
// Use lower_bound to avoid doing the search twice for missing keys. // Use lower_bound to avoid doing the search twice for missing keys.
auto found = cur->dict_.lower_bound(path_component); auto found = cur->dict().lower_bound(path_component);
if (found == cur->dict_.end() || found->first != path_component) { if (found == cur->dict().end() || found->first != path_component) {
// No key found, insert one. // No key found, insert one.
auto inserted = cur->dict_.try_emplace( auto inserted = cur->dict().try_emplace(
found, path_component, std::make_unique<Value>(Type::DICTIONARY)); found, path_component, std::make_unique<Value>(Type::DICTIONARY));
cur = inserted->second.get(); cur = inserted->second.get();
} else { } else {
...@@ -1212,13 +1053,13 @@ DictionaryValue::DictionaryValue(DictStorage&& in_dict) noexcept ...@@ -1212,13 +1053,13 @@ DictionaryValue::DictionaryValue(DictStorage&& in_dict) noexcept
bool DictionaryValue::HasKey(StringPiece key) const { bool DictionaryValue::HasKey(StringPiece key) const {
DCHECK(IsStringUTF8AllowingNoncharacters(key)); DCHECK(IsStringUTF8AllowingNoncharacters(key));
auto current_entry = dict_.find(key); auto current_entry = dict().find(key);
DCHECK((current_entry == dict_.end()) || current_entry->second); DCHECK((current_entry == dict().end()) || current_entry->second);
return current_entry != dict_.end(); return current_entry != dict().end();
} }
void DictionaryValue::Clear() { void DictionaryValue::Clear() {
dict_.clear(); dict().clear();
} }
Value* DictionaryValue::Set(StringPiece path, std::unique_ptr<Value> in_value) { Value* DictionaryValue::Set(StringPiece path, std::unique_ptr<Value> in_value) {
...@@ -1287,7 +1128,7 @@ Value* DictionaryValue::SetWithoutPathExpansion( ...@@ -1287,7 +1128,7 @@ Value* DictionaryValue::SetWithoutPathExpansion(
std::unique_ptr<Value> in_value) { std::unique_ptr<Value> in_value) {
// NOTE: We can't use |insert_or_assign| here, as only |try_emplace| does // NOTE: We can't use |insert_or_assign| here, as only |try_emplace| does
// an explicit conversion from StringPiece to std::string if necessary. // an explicit conversion from StringPiece to std::string if necessary.
auto result = dict_.try_emplace(key, std::move(in_value)); auto result = dict().try_emplace(key, std::move(in_value));
if (!result.second) { if (!result.second) {
// in_value is guaranteed to be still intact at this point. // in_value is guaranteed to be still intact at this point.
result.first->second = std::move(in_value); result.first->second = std::move(in_value);
...@@ -1295,8 +1136,7 @@ Value* DictionaryValue::SetWithoutPathExpansion( ...@@ -1295,8 +1136,7 @@ Value* DictionaryValue::SetWithoutPathExpansion(
return result.first->second.get(); return result.first->second.get();
} }
bool DictionaryValue::Get(StringPiece path, bool DictionaryValue::Get(StringPiece path, const Value** out_value) const {
const Value** out_value) const {
DCHECK(IsStringUTF8AllowingNoncharacters(path)); DCHECK(IsStringUTF8AllowingNoncharacters(path));
const Value* value = FindPath(path); const Value* value = FindPath(path);
if (!value) if (!value)
...@@ -1306,7 +1146,7 @@ bool DictionaryValue::Get(StringPiece path, ...@@ -1306,7 +1146,7 @@ bool DictionaryValue::Get(StringPiece path,
return true; return true;
} }
bool DictionaryValue::Get(StringPiece path, Value** out_value) { bool DictionaryValue::Get(StringPiece path, Value** out_value) {
return as_const(*this).Get(path, const_cast<const Value**>(out_value)); return as_const(*this).Get(path, const_cast<const Value**>(out_value));
} }
...@@ -1423,8 +1263,8 @@ bool DictionaryValue::GetList(StringPiece path, ListValue** out_value) { ...@@ -1423,8 +1263,8 @@ bool DictionaryValue::GetList(StringPiece path, ListValue** out_value) {
bool DictionaryValue::GetWithoutPathExpansion(StringPiece key, bool DictionaryValue::GetWithoutPathExpansion(StringPiece key,
const Value** out_value) const { const Value** out_value) const {
DCHECK(IsStringUTF8AllowingNoncharacters(key)); DCHECK(IsStringUTF8AllowingNoncharacters(key));
auto entry_iterator = dict_.find(key); auto entry_iterator = dict().find(key);
if (entry_iterator == dict_.end()) if (entry_iterator == dict().end())
return false; return false;
if (out_value) if (out_value)
...@@ -1546,13 +1386,13 @@ bool DictionaryValue::RemoveWithoutPathExpansion( ...@@ -1546,13 +1386,13 @@ bool DictionaryValue::RemoveWithoutPathExpansion(
StringPiece key, StringPiece key,
std::unique_ptr<Value>* out_value) { std::unique_ptr<Value>* out_value) {
DCHECK(IsStringUTF8AllowingNoncharacters(key)); DCHECK(IsStringUTF8AllowingNoncharacters(key));
auto entry_iterator = dict_.find(key); auto entry_iterator = dict().find(key);
if (entry_iterator == dict_.end()) if (entry_iterator == dict().end())
return false; return false;
if (out_value) if (out_value)
*out_value = std::move(entry_iterator->second); *out_value = std::move(entry_iterator->second);
dict_.erase(entry_iterator); dict().erase(entry_iterator);
return true; return true;
} }
...@@ -1568,8 +1408,7 @@ bool DictionaryValue::RemovePath(StringPiece path, ...@@ -1568,8 +1408,7 @@ bool DictionaryValue::RemovePath(StringPiece path,
DictionaryValue* subdict = nullptr; DictionaryValue* subdict = nullptr;
if (!GetDictionary(subdict_path, &subdict)) if (!GetDictionary(subdict_path, &subdict))
return false; return false;
result = subdict->RemovePath(path.substr(delimiter_position + 1), result = subdict->RemovePath(path.substr(delimiter_position + 1), out_value);
out_value);
if (result && subdict->empty()) if (result && subdict->empty())
RemoveKey(subdict_path); RemoveKey(subdict_path);
...@@ -1587,22 +1426,22 @@ std::unique_ptr<DictionaryValue> DictionaryValue::DeepCopyWithoutEmptyChildren() ...@@ -1587,22 +1426,22 @@ std::unique_ptr<DictionaryValue> DictionaryValue::DeepCopyWithoutEmptyChildren()
void DictionaryValue::Swap(DictionaryValue* other) { void DictionaryValue::Swap(DictionaryValue* other) {
CHECK(other->is_dict()); CHECK(other->is_dict());
dict_.swap(other->dict_); dict().swap(other->dict());
} }
DictionaryValue::Iterator::Iterator(const DictionaryValue& target) DictionaryValue::Iterator::Iterator(const DictionaryValue& target)
: target_(target), it_(target.dict_.begin()) {} : target_(target), it_(target.dict().begin()) {}
DictionaryValue::Iterator::Iterator(const Iterator& other) = default; DictionaryValue::Iterator::Iterator(const Iterator& other) = default;
DictionaryValue::Iterator::~Iterator() = default; DictionaryValue::Iterator::~Iterator() = default;
DictionaryValue* DictionaryValue::DeepCopy() const { DictionaryValue* DictionaryValue::DeepCopy() const {
return new DictionaryValue(dict_); return new DictionaryValue(dict());
} }
std::unique_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const { std::unique_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const {
return std::make_unique<DictionaryValue>(dict_); return std::make_unique<DictionaryValue>(dict());
} }
///////////////////// ListValue //////////////////// ///////////////////// ListValue ////////////////////
...@@ -1623,30 +1462,30 @@ ListValue::ListValue(ListStorage&& in_list) noexcept ...@@ -1623,30 +1462,30 @@ ListValue::ListValue(ListStorage&& in_list) noexcept
: Value(std::move(in_list)) {} : Value(std::move(in_list)) {}
void ListValue::Clear() { void ListValue::Clear() {
list_.clear(); list().clear();
} }
void ListValue::Reserve(size_t n) { void ListValue::Reserve(size_t n) {
list_.reserve(n); list().reserve(n);
} }
bool ListValue::Set(size_t index, std::unique_ptr<Value> in_value) { bool ListValue::Set(size_t index, std::unique_ptr<Value> in_value) {
if (!in_value) if (!in_value)
return false; return false;
if (index >= list_.size()) if (index >= list().size())
list_.resize(index + 1); list().resize(index + 1);
list_[index] = std::move(*in_value); list()[index] = std::move(*in_value);
return true; return true;
} }
bool ListValue::Get(size_t index, const Value** out_value) const { bool ListValue::Get(size_t index, const Value** out_value) const {
if (index >= list_.size()) if (index >= list().size())
return false; return false;
if (out_value) if (out_value)
*out_value = &list_[index]; *out_value = &list()[index];
return true; return true;
} }
...@@ -1731,26 +1570,26 @@ bool ListValue::GetList(size_t index, ListValue** out_value) { ...@@ -1731,26 +1570,26 @@ bool ListValue::GetList(size_t index, ListValue** out_value) {
} }
bool ListValue::Remove(size_t index, std::unique_ptr<Value>* out_value) { bool ListValue::Remove(size_t index, std::unique_ptr<Value>* out_value) {
if (index >= list_.size()) if (index >= list().size())
return false; return false;
if (out_value) if (out_value)
*out_value = std::make_unique<Value>(std::move(list_[index])); *out_value = std::make_unique<Value>(std::move(list()[index]));
list_.erase(list_.begin() + index); list().erase(list().begin() + index);
return true; return true;
} }
bool ListValue::Remove(const Value& value, size_t* index) { bool ListValue::Remove(const Value& value, size_t* index) {
auto it = std::find(list_.begin(), list_.end(), value); auto it = std::find(list().begin(), list().end(), value);
if (it == list_.end()) if (it == list().end())
return false; return false;
if (index) if (index)
*index = std::distance(list_.begin(), it); *index = std::distance(list().begin(), it);
list_.erase(it); list().erase(it);
return true; return true;
} }
...@@ -1759,63 +1598,63 @@ ListValue::iterator ListValue::Erase(iterator iter, ...@@ -1759,63 +1598,63 @@ ListValue::iterator ListValue::Erase(iterator iter,
if (out_value) if (out_value)
*out_value = std::make_unique<Value>(std::move(*iter)); *out_value = std::make_unique<Value>(std::move(*iter));
auto list_iter = list_.begin() + (iter - GetList().begin()); auto list_iter = list().begin() + (iter - GetList().begin());
CHECK(list_iter != list_.end()); CHECK(list_iter != list().end());
list_iter = list_.erase(list_iter); list_iter = list().erase(list_iter);
return GetList().begin() + (list_iter - list_.begin()); return GetList().begin() + (list_iter - list().begin());
} }
void ListValue::Append(std::unique_ptr<Value> in_value) { void ListValue::Append(std::unique_ptr<Value> in_value) {
list_.push_back(std::move(*in_value)); list().push_back(std::move(*in_value));
} }
void ListValue::AppendBoolean(bool in_value) { void ListValue::AppendBoolean(bool in_value) {
list_.emplace_back(in_value); list().emplace_back(in_value);
} }
void ListValue::AppendInteger(int in_value) { void ListValue::AppendInteger(int in_value) {
list_.emplace_back(in_value); list().emplace_back(in_value);
} }
void ListValue::AppendDouble(double in_value) { void ListValue::AppendDouble(double in_value) {
list_.emplace_back(in_value); list().emplace_back(in_value);
} }
void ListValue::AppendString(StringPiece in_value) { void ListValue::AppendString(StringPiece in_value) {
list_.emplace_back(in_value); list().emplace_back(in_value);
} }
void ListValue::AppendString(const string16& in_value) { void ListValue::AppendString(const string16& in_value) {
list_.emplace_back(in_value); list().emplace_back(in_value);
} }
void ListValue::AppendStrings(const std::vector<std::string>& in_values) { void ListValue::AppendStrings(const std::vector<std::string>& in_values) {
list_.reserve(list_.size() + in_values.size()); list().reserve(list().size() + in_values.size());
for (const auto& in_value : in_values) for (const auto& in_value : in_values)
list_.emplace_back(in_value); list().emplace_back(in_value);
} }
void ListValue::AppendStrings(const std::vector<string16>& in_values) { void ListValue::AppendStrings(const std::vector<string16>& in_values) {
list_.reserve(list_.size() + in_values.size()); list().reserve(list().size() + in_values.size());
for (const auto& in_value : in_values) for (const auto& in_value : in_values)
list_.emplace_back(in_value); list().emplace_back(in_value);
} }
bool ListValue::AppendIfNotPresent(std::unique_ptr<Value> in_value) { bool ListValue::AppendIfNotPresent(std::unique_ptr<Value> in_value) {
DCHECK(in_value); DCHECK(in_value);
if (Contains(list_, *in_value)) if (Contains(list(), *in_value))
return false; return false;
list_.push_back(std::move(*in_value)); list().push_back(std::move(*in_value));
return true; return true;
} }
bool ListValue::Insert(size_t index, std::unique_ptr<Value> in_value) { bool ListValue::Insert(size_t index, std::unique_ptr<Value> in_value) {
DCHECK(in_value); DCHECK(in_value);
if (index > list_.size()) if (index > list().size())
return false; return false;
list_.insert(list_.begin() + index, std::move(*in_value)); list().insert(list().begin() + index, std::move(*in_value));
return true; return true;
} }
...@@ -1825,15 +1664,15 @@ ListValue::const_iterator ListValue::Find(const Value& value) const { ...@@ -1825,15 +1664,15 @@ ListValue::const_iterator ListValue::Find(const Value& value) const {
void ListValue::Swap(ListValue* other) { void ListValue::Swap(ListValue* other) {
CHECK(other->is_list()); CHECK(other->is_list());
list_.swap(other->list_); list().swap(other->list());
} }
ListValue* ListValue::DeepCopy() const { ListValue* ListValue::DeepCopy() const {
return new ListValue(list_); return new ListValue(list());
} }
std::unique_ptr<ListValue> ListValue::CreateDeepCopy() const { std::unique_ptr<ListValue> ListValue::CreateDeepCopy() const {
return std::make_unique<ListValue>(list_); return std::make_unique<ListValue>(list());
} }
ValueSerializer::~ValueSerializer() = default; ValueSerializer::~ValueSerializer() = default;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/value_iterators.h" #include "base/value_iterators.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
namespace base { namespace base {
...@@ -89,9 +90,6 @@ class BASE_EXPORT Value { ...@@ -89,9 +90,6 @@ class BASE_EXPORT Value {
using ListView = CheckedContiguousRange<ListStorage>; using ListView = CheckedContiguousRange<ListStorage>;
using ConstListView = CheckedContiguousConstRange<ListStorage>; using ConstListView = CheckedContiguousConstRange<ListStorage>;
// See technical note below explaining why this is used.
using DoubleStorage = struct { alignas(4) char v[sizeof(double)]; };
enum class Type : unsigned char { enum class Type : unsigned char {
NONE = 0, NONE = 0,
BOOLEAN, BOOLEAN,
...@@ -120,11 +118,8 @@ class BASE_EXPORT Value { ...@@ -120,11 +118,8 @@ class BASE_EXPORT Value {
static const DictionaryValue& AsDictionaryValue(const Value& val); static const DictionaryValue& AsDictionaryValue(const Value& val);
static const ListValue& AsListValue(const Value& val); static const ListValue& AsListValue(const Value& val);
Value() noexcept;
Value(Value&& that) noexcept; Value(Value&& that) noexcept;
Value() noexcept {} // A null value. NOLINT(modernize-use-equals-default)
// Fun fact: using '= default' above instead of '{}' does not work because
// the compiler complains that the default constructor was deleted since
// the inner union contains fields with non-default constructors.
// Value's copy constructor and copy assignment operator are deleted. Use this // Value's copy constructor and copy assignment operator are deleted. Use this
// to obtain a deep copy explicitly. // to obtain a deep copy explicitly.
...@@ -163,7 +158,7 @@ class BASE_EXPORT Value { ...@@ -163,7 +158,7 @@ class BASE_EXPORT Value {
static const char* GetTypeName(Type type); static const char* GetTypeName(Type type);
// Returns the type of the value stored by the current Value object. // Returns the type of the value stored by the current Value object.
Type type() const { return type_; } Type type() const { return static_cast<Type>(data_.index()); }
// Returns true if the current object represents a given type. // Returns true if the current object represents a given type.
bool is_none() const { return type() == Type::NONE; } bool is_none() const { return type() == Type::NONE; }
...@@ -192,7 +187,7 @@ class BASE_EXPORT Value { ...@@ -192,7 +187,7 @@ class BASE_EXPORT Value {
// Transfers ownership of the underlying list to the caller. Subsequent // Transfers ownership of the underlying list to the caller. Subsequent
// calls to GetList() will return an empty list. // calls to GetList() will return an empty list.
// Note: This CHECKs that type() is Type::LIST. // Note: This requires that type() is Type::LIST.
ListStorage TakeList(); ListStorage TakeList();
// Appends |value| to the end of the list. // Appends |value| to the end of the list.
...@@ -215,32 +210,31 @@ class BASE_EXPORT Value { ...@@ -215,32 +210,31 @@ class BASE_EXPORT Value {
// Erases the Value pointed to by |iter|. Returns false if |iter| is out of // Erases the Value pointed to by |iter|. Returns false if |iter| is out of
// bounds. // bounds.
// Note: This CHECKs that type() is Type::LIST. // Note: This requires that type() is Type::LIST.
bool EraseListIter(CheckedContiguousConstIterator<Value> iter); bool EraseListIter(CheckedContiguousConstIterator<Value> iter);
// Erases all Values that compare equal to |val|. Returns the number of // Erases all Values that compare equal to |val|. Returns the number of
// deleted Values. // deleted Values.
// Note: This CHECKs that type() is Type::LIST. // Note: This requires that type() is Type::LIST.
size_t EraseListValue(const Value& val); size_t EraseListValue(const Value& val);
// Erases all Values for which |pred| returns true. Returns the number of // Erases all Values for which |pred| returns true. Returns the number of
// deleted Values. // deleted Values.
// Note: This CHECKs that type() is Type::LIST. // Note: This requires that type() is Type::LIST.
template <typename Predicate> template <typename Predicate>
size_t EraseListValueIf(Predicate pred) { size_t EraseListValueIf(Predicate pred) {
CHECK(is_list()); return base::EraseIf(list(), pred);
return base::EraseIf(list_, pred);
} }
// Erases all Values from the list. // Erases all Values from the list.
// Note: This CHECKs that type() is Type::LIST. // Note: This requires that type() is Type::LIST.
void ClearList(); void ClearList();
// |FindKey| looks up |key| in the underlying dictionary. If found, it returns // |FindKey| looks up |key| in the underlying dictionary. If found, it returns
// a pointer to the element. Otherwise it returns nullptr. // a pointer to the element. Otherwise it returns nullptr.
// returned. Callers are expected to perform a check against null before using // returned. Callers are expected to perform a check against null before using
// the pointer. // the pointer.
// Note: This CHECKs that type() is Type::DICTIONARY. // Note: This requires that type() is Type::DICTIONARY.
// //
// Example: // Example:
// auto* found = FindKey("foo"); // auto* found = FindKey("foo");
...@@ -252,7 +246,7 @@ class BASE_EXPORT Value { ...@@ -252,7 +246,7 @@ class BASE_EXPORT Value {
// different type nullptr is returned. // different type nullptr is returned.
// Callers are expected to perform a check against null before using the // Callers are expected to perform a check against null before using the
// pointer. // pointer.
// Note: This CHECKs that type() is Type::DICTIONARY. // Note: This requires that type() is Type::DICTIONARY.
// //
// Example: // Example:
// auto* found = FindKey("foo", Type::DOUBLE); // auto* found = FindKey("foo", Type::DOUBLE);
...@@ -286,7 +280,7 @@ class BASE_EXPORT Value { ...@@ -286,7 +280,7 @@ class BASE_EXPORT Value {
// |SetKey| looks up |key| in the underlying dictionary and sets the mapped // |SetKey| looks up |key| in the underlying dictionary and sets the mapped
// value to |value|. If |key| could not be found, a new element is inserted. // value to |value|. If |key| could not be found, a new element is inserted.
// A pointer to the modified item is returned. // A pointer to the modified item is returned.
// Note: This CHECKs that type() is Type::DICTIONARY. // Note: This requires that type() is Type::DICTIONARY.
// Note: Prefer Set<Type>Key() for simple values. // Note: Prefer Set<Type>Key() for simple values.
// //
// Example: // Example:
...@@ -315,7 +309,7 @@ class BASE_EXPORT Value { ...@@ -315,7 +309,7 @@ class BASE_EXPORT Value {
// failure, e.g. the key does not exist, false is returned and the underlying // failure, e.g. the key does not exist, false is returned and the underlying
// dictionary is not changed. In case of success, |key| is deleted from the // dictionary is not changed. In case of success, |key| is deleted from the
// dictionary and the method returns true. // dictionary and the method returns true.
// Note: This CHECKs that type() is Type::DICTIONARY. // Note: This requires that type() is Type::DICTIONARY.
// //
// Example: // Example:
// bool success = dict.RemoveKey("foo"); // bool success = dict.RemoveKey("foo");
...@@ -325,7 +319,7 @@ class BASE_EXPORT Value { ...@@ -325,7 +319,7 @@ class BASE_EXPORT Value {
// failure, e.g. the key does not exist, nullopt is returned and the // failure, e.g. the key does not exist, nullopt is returned and the
// underlying dictionary is not changed. In case of success, |key| is deleted // underlying dictionary is not changed. In case of success, |key| is deleted
// from the dictionary and the method returns the extracted Value. // from the dictionary and the method returns the extracted Value.
// Note: This CHECKs that type() is Type::DICTIONARY. // Note: This requires that type() is Type::DICTIONARY.
// //
// Example: // Example:
// Optional<Value> maybe_value = dict.ExtractKey("foo"); // Optional<Value> maybe_value = dict.ExtractKey("foo");
...@@ -481,7 +475,7 @@ class BASE_EXPORT Value { ...@@ -481,7 +475,7 @@ class BASE_EXPORT Value {
// passed in dictionary takes precedence and data already present will be // passed in dictionary takes precedence and data already present will be
// replaced. Values within |dictionary| are deep-copied, so |dictionary| may // replaced. Values within |dictionary| are deep-copied, so |dictionary| may
// be freed any time after this call. // be freed any time after this call.
// Note: This CHECKs that type() and dictionary->type() is Type::DICTIONARY. // Note: This requires that type() and dictionary->type() is Type::DICTIONARY.
void MergeDictionary(const Value* dictionary); void MergeDictionary(const Value* dictionary);
// These methods allow the convenient retrieval of the contents of the Value. // These methods allow the convenient retrieval of the contents of the Value.
...@@ -539,6 +533,13 @@ class BASE_EXPORT Value { ...@@ -539,6 +533,13 @@ class BASE_EXPORT Value {
size_t EstimateMemoryUsage() const; size_t EstimateMemoryUsage() const;
protected: protected:
// Checked convenience accessors for dict and list.
const DictStorage& dict() const { return absl::get<DictStorage>(data_); }
DictStorage& dict() { return absl::get<DictStorage>(data_); }
const ListStorage& list() const { return absl::get<ListStorage>(data_); }
ListStorage& list() { return absl::get<ListStorage>(data_); }
private:
// Special case for doubles, which are aligned to 8 bytes on some // Special case for doubles, which are aligned to 8 bytes on some
// 32-bit architectures. In this case, a simple declaration as a // 32-bit architectures. In this case, a simple declaration as a
// double member would make the whole union 8 byte-aligned, which // double member would make the whole union 8 byte-aligned, which
...@@ -547,29 +548,30 @@ class BASE_EXPORT Value { ...@@ -547,29 +548,30 @@ class BASE_EXPORT Value {
// //
// To override this, store the value as an array of 32-bit integers, and // To override this, store the value as an array of 32-bit integers, and
// perform the appropriate bit casts when reading / writing to it. // perform the appropriate bit casts when reading / writing to it.
Type type_ = Type::NONE; using DoubleStorage = struct { alignas(4) char v[sizeof(double)]; };
union { // Internal constructors, allowing the simplify the implementation of Clone().
bool bool_value_; explicit Value(absl::monostate);
int int_value_; explicit Value(DoubleStorage storage);
DoubleStorage double_value_;
std::string string_value_;
BlobStorage binary_value_;
DictStorage dict_;
ListStorage list_;
};
private:
friend class ValuesTest_SizeOfValue_Test; friend class ValuesTest_SizeOfValue_Test;
double AsDoubleInternal() const; double AsDoubleInternal() const;
void InternalMoveConstructFrom(Value&& that);
void InternalCleanup();
// NOTE: Using a movable reference here is done for performance (it avoids // NOTE: Using a movable reference here is done for performance (it avoids
// creating + moving + destroying a temporary unique ptr). // creating + moving + destroying a temporary unique ptr).
Value* SetKeyInternal(StringPiece key, std::unique_ptr<Value>&& val_ptr); Value* SetKeyInternal(StringPiece key, std::unique_ptr<Value>&& val_ptr);
Value* SetPathInternal(StringPiece path, std::unique_ptr<Value>&& value_ptr); Value* SetPathInternal(StringPiece path, std::unique_ptr<Value>&& value_ptr);
absl::variant<absl::monostate,
bool,
int,
DoubleStorage,
std::string,
BlobStorage,
DictStorage,
ListStorage>
data_;
DISALLOW_COPY_AND_ASSIGN(Value); DISALLOW_COPY_AND_ASSIGN(Value);
}; };
...@@ -593,10 +595,10 @@ class BASE_EXPORT DictionaryValue : public Value { ...@@ -593,10 +595,10 @@ class BASE_EXPORT DictionaryValue : public Value {
bool HasKey(StringPiece key) const; bool HasKey(StringPiece key) const;
// Returns the number of Values in this dictionary. // Returns the number of Values in this dictionary.
size_t size() const { return dict_.size(); } size_t size() const { return dict().size(); }
// Returns whether the dictionary is empty. // Returns whether the dictionary is empty.
bool empty() const { return dict_.empty(); } bool empty() const { return dict().empty(); }
// Clears any current contents of this dictionary. // Clears any current contents of this dictionary.
void Clear(); void Clear();
...@@ -672,8 +674,7 @@ class BASE_EXPORT DictionaryValue : public Value { ...@@ -672,8 +674,7 @@ class BASE_EXPORT DictionaryValue : public Value {
// DEPRECATED, use Value::FindBlobPath(path) instead. // DEPRECATED, use Value::FindBlobPath(path) instead.
bool GetBinary(StringPiece path, Value** out_value); bool GetBinary(StringPiece path, Value** out_value);
// DEPRECATED, use Value::FindPath(path) and Value's Dictionary API instead. // DEPRECATED, use Value::FindPath(path) and Value's Dictionary API instead.
bool GetDictionary(StringPiece path, bool GetDictionary(StringPiece path, const DictionaryValue** out_value) const;
const DictionaryValue** out_value) const;
// DEPRECATED, use Value::FindPath(path) and Value's Dictionary API instead. // DEPRECATED, use Value::FindPath(path) and Value's Dictionary API instead.
bool GetDictionary(StringPiece path, DictionaryValue** out_value); bool GetDictionary(StringPiece path, DictionaryValue** out_value);
// DEPRECATED, use Value::FindPath(path) and Value::GetList() instead. // DEPRECATED, use Value::FindPath(path) and Value::GetList() instead.
...@@ -752,7 +753,7 @@ class BASE_EXPORT DictionaryValue : public Value { ...@@ -752,7 +753,7 @@ class BASE_EXPORT DictionaryValue : public Value {
Iterator(const Iterator& other); Iterator(const Iterator& other);
~Iterator(); ~Iterator();
bool IsAtEnd() const { return it_ == target_.dict_.end(); } bool IsAtEnd() const { return it_ == target_.end(); }
void Advance() { ++it_; } void Advance() { ++it_; }
const std::string& key() const { return it_->first; } const std::string& key() const { return it_->first; }
...@@ -765,12 +766,12 @@ class BASE_EXPORT DictionaryValue : public Value { ...@@ -765,12 +766,12 @@ class BASE_EXPORT DictionaryValue : public Value {
// Iteration. // Iteration.
// DEPRECATED, use Value::DictItems() instead. // DEPRECATED, use Value::DictItems() instead.
iterator begin() { return dict_.begin(); } iterator begin() { return dict().begin(); }
iterator end() { return dict_.end(); } iterator end() { return dict().end(); }
// DEPRECATED, use Value::DictItems() instead. // DEPRECATED, use Value::DictItems() instead.
const_iterator begin() const { return dict_.begin(); } const_iterator begin() const { return dict().begin(); }
const_iterator end() const { return dict_.end(); } const_iterator end() const { return dict().end(); }
// DEPRECATED, use Value::Clone() instead. // DEPRECATED, use Value::Clone() instead.
// TODO(crbug.com/646113): Delete this and migrate callsites. // TODO(crbug.com/646113): Delete this and migrate callsites.
...@@ -799,11 +800,11 @@ class BASE_EXPORT ListValue : public Value { ...@@ -799,11 +800,11 @@ class BASE_EXPORT ListValue : public Value {
// Returns the number of Values in this list. // Returns the number of Values in this list.
// DEPRECATED, use GetList()::size() instead. // DEPRECATED, use GetList()::size() instead.
size_t GetSize() const { return list_.size(); } size_t GetSize() const { return list().size(); }
// Returns whether the list is empty. // Returns whether the list is empty.
// DEPRECATED, use GetList()::empty() instead. // DEPRECATED, use GetList()::empty() instead.
bool empty() const { return list_.empty(); } bool empty() const { return list().empty(); }
// Reserves storage for at least |n| values. // Reserves storage for at least |n| values.
// DEPRECATED, first construct a base::Value::ListStorage and use // DEPRECATED, first construct a base::Value::ListStorage and use
......
...@@ -36,74 +36,23 @@ namespace base { ...@@ -36,74 +36,23 @@ namespace base {
// This test is only enabled when NDEBUG is defined. This way the test will not // This test is only enabled when NDEBUG is defined. This way the test will not
// fail in debug builds that sometimes contain larger versions of the standard // fail in debug builds that sometimes contain larger versions of the standard
// containers used inside base::Value. // containers used inside base::Value.
#if defined(NDEBUG)
TEST(ValuesTest, SizeOfValue) { TEST(ValuesTest, SizeOfValue) {
#define INNER_TYPES_LIST(X) \ static_assert(
X(bool, bool_value_) \ std::max({alignof(size_t), alignof(bool), alignof(int),
X(int, int_value_) \ alignof(Value::DoubleStorage), alignof(std::string),
X(Value::DoubleStorage, double_value_) \ alignof(Value::BlobStorage), alignof(Value::ListStorage),
X(std::string, string_value_) \ alignof(Value::DictStorage)}) == alignof(Value),
X(Value::BlobStorage, binary_value_) \ "Value does not have smallest possible alignof");
X(Value::ListStorage, list_) \
X(Value::DictStorage, dict_)
#define INNER_FIELD_ALIGNMENT(type, value) alignof(type),
// The maximum alignment of each inner struct value field inside base::Value
size_t max_inner_value_alignment =
std::max({INNER_TYPES_LIST(INNER_FIELD_ALIGNMENT)});
// Check that base::Value has the smallest alignment possible. This would
// fail if the header would contain something that has a larger alignment
// than necessary.
EXPECT_EQ(max_inner_value_alignment, alignof(Value));
// Find the offset of each inner value. Which should normally not be
// larger than 4. Note that we use std::max(4, ...) because bool_value_
// could be stored just after the |bool_type_| field, with an offset of
// 1, and that would be ok.
#define INNER_VALUE_START_OFFSET(type, value) offsetof(Value, value),
size_t min_inner_value_offset =
std::min({INNER_TYPES_LIST(INNER_VALUE_START_OFFSET)});
// Inner fields may contain pointers, which have an alignment of 8
// on most 64-bit platforms.
size_t expected_min_offset = alignof(void*);
EXPECT_EQ(expected_min_offset, min_inner_value_offset);
// Ensure that base::Value is not larger than necessary, i.e. that there is
// no un-necessary padding after the structs due to alignment constraints of
// one of the inner fields.
#define INNER_STRUCT_END_OFFSET(type, value) \
offsetof(Value, value) + sizeof(type),
// The maximum size in bytes of each inner struct inside base::Value,
size_t max_inner_struct_end_offset =
std::max({INNER_TYPES_LIST(INNER_STRUCT_END_OFFSET)});
// The expected value size.
size_t expected_value_size =
bits::Align(max_inner_struct_end_offset, alignof(Value));
EXPECT_EQ(expected_value_size, sizeof(Value));
if (min_inner_value_offset != expected_min_offset ||
expected_value_size != sizeof(Value)) {
// The following are useful to understand what's wrong when the EXPECT_EQ()
// above actually fail.
#define PRINT_INNER_FIELD_INFO(x, y) \
LOG(INFO) << #y " type=" #x " offset=" << offsetof(Value, y) \
<< " size=" << sizeof(x) << " align=" << alignof(x);
LOG(INFO) << "Value size=" << sizeof(Value) << " align=" << alignof(Value);
INNER_TYPES_LIST(PRINT_INNER_FIELD_INFO)
LOG(INFO) << "max_inner_struct_end_offset=" << max_inner_struct_end_offset;
}
}
#endif // NDEBUG static_assert(
sizeof(size_t) +
std::max({sizeof(bool), sizeof(int), sizeof(Value::DoubleStorage),
sizeof(std::string), sizeof(Value::BlobStorage),
sizeof(Value::ListStorage),
sizeof(Value::DictStorage)}) ==
sizeof(Value),
"Value does not have smallest possible sizeof");
}
TEST(ValuesTest, TestNothrow) { TEST(ValuesTest, TestNothrow) {
static_assert(std::is_nothrow_move_constructible<Value>::value, static_assert(std::is_nothrow_move_constructible<Value>::value,
...@@ -240,6 +189,18 @@ TEST(ValuesTest, ConstructListFromStorage) { ...@@ -240,6 +189,18 @@ TEST(ValuesTest, ConstructListFromStorage) {
} }
} }
TEST(ValuesTest, HardenTests) {
Value value;
ASSERT_EQ(value.type(), Value::Type::NONE);
EXPECT_DEATH_IF_SUPPORTED(value.GetBool(), "");
EXPECT_DEATH_IF_SUPPORTED(value.GetInt(), "");
EXPECT_DEATH_IF_SUPPORTED(value.GetDouble(), "");
EXPECT_DEATH_IF_SUPPORTED(value.GetString(), "");
EXPECT_DEATH_IF_SUPPORTED(value.GetBlob(), "");
EXPECT_DEATH_IF_SUPPORTED(value.DictItems(), "");
EXPECT_DEATH_IF_SUPPORTED(value.GetList(), "");
}
// Group of tests for the copy constructors and copy-assigmnent. For equality // Group of tests for the copy constructors and copy-assigmnent. For equality
// checks comparisons of the interesting fields are done instead of relying on // checks comparisons of the interesting fields are done instead of relying on
// Equals being correct. // Equals being correct.
...@@ -1474,8 +1435,8 @@ TEST(ValuesTest, ListRemoval) { ...@@ -1474,8 +1435,8 @@ TEST(ValuesTest, ListRemoval) {
ListValue list; ListValue list;
list.Append(std::make_unique<Value>()); list.Append(std::make_unique<Value>());
EXPECT_EQ(1U, list.GetSize()); EXPECT_EQ(1U, list.GetSize());
EXPECT_FALSE(list.Remove(std::numeric_limits<size_t>::max(), EXPECT_FALSE(
&removed_item)); list.Remove(std::numeric_limits<size_t>::max(), &removed_item));
EXPECT_FALSE(list.Remove(1, &removed_item)); EXPECT_FALSE(list.Remove(1, &removed_item));
EXPECT_TRUE(list.Remove(0, &removed_item)); EXPECT_TRUE(list.Remove(0, &removed_item));
ASSERT_TRUE(removed_item); ASSERT_TRUE(removed_item);
...@@ -2080,7 +2041,7 @@ TEST(ValuesTest, RemoveEmptyChildren) { ...@@ -2080,7 +2041,7 @@ TEST(ValuesTest, RemoveEmptyChildren) {
root = root->DeepCopyWithoutEmptyChildren(); root = root->DeepCopyWithoutEmptyChildren();
EXPECT_EQ(3U, root->size()); EXPECT_EQ(3U, root->size());
ListValue* inner_value, *inner_value2; ListValue *inner_value, *inner_value2;
EXPECT_TRUE(root->GetList("list_with_empty_children", &inner_value)); EXPECT_TRUE(root->GetList("list_with_empty_children", &inner_value));
EXPECT_EQ(1U, inner_value->GetSize()); // Dictionary was pruned. EXPECT_EQ(1U, inner_value->GetSize()); // Dictionary was pruned.
EXPECT_TRUE(inner_value->GetList(0, &inner_value2)); EXPECT_TRUE(inner_value->GetList(0, &inner_value2));
...@@ -2126,8 +2087,8 @@ TEST(ValuesTest, MergeDictionary) { ...@@ -2126,8 +2087,8 @@ TEST(ValuesTest, MergeDictionary) {
EXPECT_TRUE(res_sub_dict->GetString("sub_base_key", &sub_base_key_value)); EXPECT_TRUE(res_sub_dict->GetString("sub_base_key", &sub_base_key_value));
EXPECT_EQ("sub_base_key_value_base", sub_base_key_value); // Preserved. EXPECT_EQ("sub_base_key_value_base", sub_base_key_value); // Preserved.
std::string sub_collide_key_value; std::string sub_collide_key_value;
EXPECT_TRUE(res_sub_dict->GetString("sub_collide_key", EXPECT_TRUE(
&sub_collide_key_value)); res_sub_dict->GetString("sub_collide_key", &sub_collide_key_value));
EXPECT_EQ("sub_collide_key_value_merge", sub_collide_key_value); // Replaced. EXPECT_EQ("sub_collide_key_value_merge", sub_collide_key_value); // Replaced.
std::string sub_merge_key_value; std::string sub_merge_key_value;
EXPECT_TRUE(res_sub_dict->GetString("sub_merge_key", &sub_merge_key_value)); EXPECT_TRUE(res_sub_dict->GetString("sub_merge_key", &sub_merge_key_value));
......
...@@ -37,7 +37,6 @@ source_set("common") { ...@@ -37,7 +37,6 @@ source_set("common") {
deps = [ deps = [
":logging_definitions", ":logging_definitions",
":scoped_timed_task_logger", ":scoped_timed_task_logger",
"//base",
"//chrome/chrome_cleaner/constants:common_strings", "//chrome/chrome_cleaner/constants:common_strings",
"//chrome/chrome_cleaner/constants:version_header", "//chrome/chrome_cleaner/constants:version_header",
"//chrome/chrome_cleaner/http", # For safe_browsing_reporter "//chrome/chrome_cleaner/http", # For safe_browsing_reporter
...@@ -54,6 +53,7 @@ source_set("common") { ...@@ -54,6 +53,7 @@ source_set("common") {
] ]
public_deps = [ public_deps = [
"//base",
"//chrome/chrome_cleaner/logging/proto:shared_data_proto", "//chrome/chrome_cleaner/logging/proto:shared_data_proto",
"//net/traffic_annotation:traffic_annotation", "//net/traffic_annotation:traffic_annotation",
] ]
...@@ -134,7 +134,6 @@ static_library("cleaner_logging") { ...@@ -134,7 +134,6 @@ static_library("cleaner_logging") {
":api_keys", ":api_keys",
":api_keys_header", ":api_keys_header",
":common", ":common",
"//base",
"//chrome/chrome_cleaner/chrome_utils:chrome_util_lib", "//chrome/chrome_cleaner/chrome_utils:chrome_util_lib",
"//chrome/chrome_cleaner/constants:chrome_cleanup_tool_branding_header", "//chrome/chrome_cleaner/constants:chrome_cleanup_tool_branding_header",
"//chrome/chrome_cleaner/constants:common_strings", "//chrome/chrome_cleaner/constants:common_strings",
...@@ -149,6 +148,8 @@ static_library("cleaner_logging") { ...@@ -149,6 +148,8 @@ static_library("cleaner_logging") {
"//chrome/chrome_cleaner/strings", "//chrome/chrome_cleaner/strings",
"//components/chrome_cleaner/public/constants:constants", "//components/chrome_cleaner/public/constants:constants",
] ]
public_deps = [ "//base" ]
} }
static_library("reporter_logging") { static_library("reporter_logging") {
...@@ -183,12 +184,13 @@ static_library("noop_logging") { ...@@ -183,12 +184,13 @@ static_library("noop_logging") {
deps = [ deps = [
":common", ":common",
"//base",
"//chrome/chrome_cleaner/os:common_os", "//chrome/chrome_cleaner/os:common_os",
"//chrome/chrome_cleaner/proto:shared_pup_enums_proto", "//chrome/chrome_cleaner/proto:shared_pup_enums_proto",
"//chrome/chrome_cleaner/pup_data:pup_data_base", "//chrome/chrome_cleaner/pup_data:pup_data_base",
"//components/chrome_cleaner/public/constants:constants", "//components/chrome_cleaner/public/constants:constants",
] ]
public_deps = [ "//base" ]
} }
source_set("mock_logging_service") { source_set("mock_logging_service") {
......
...@@ -28,10 +28,12 @@ static_library("common") { ...@@ -28,10 +28,12 @@ static_library("common") {
configs += [ "//build/config/compiler:wexit_time_destructors" ] configs += [ "//build/config/compiler:wexit_time_destructors" ]
public_deps = [ ":features" ] public_deps = [
":features",
"//base",
]
deps = [ deps = [
"//base",
"//ipc", "//ipc",
"//mojo/public/cpp/base", "//mojo/public/cpp/base",
"//mojo/public/cpp/bindings:struct_traits", "//mojo/public/cpp/bindings:struct_traits",
......
...@@ -50,10 +50,9 @@ component("prefs") { ...@@ -50,10 +50,9 @@ component("prefs") {
defines = [ "COMPONENTS_PREFS_IMPLEMENTATION" ] defines = [ "COMPONENTS_PREFS_IMPLEMENTATION" ]
deps = [ deps = [ "//base/util/values:values_util" ]
"//base",
"//base/util/values:values_util", public_deps = [ "//base" ]
]
if (is_android) { if (is_android) {
sources += [ sources += [
......
...@@ -13,13 +13,14 @@ static_library("safe_browsing_prefs") { ...@@ -13,13 +13,14 @@ static_library("safe_browsing_prefs") {
] ]
deps = [ deps = [
"//base:base",
"//components/pref_registry:pref_registry", "//components/pref_registry:pref_registry",
"//components/prefs", "//components/prefs",
"//components/safe_browsing/core:features", "//components/safe_browsing/core:features",
"//components/safe_browsing/core/common:thread_utils", "//components/safe_browsing/core/common:thread_utils",
"//net:net", "//net:net",
] ]
public_deps = [ "//base" ]
} }
source_set("safe_browsing_policy_handler") { source_set("safe_browsing_policy_handler") {
......
...@@ -127,9 +127,11 @@ static_library("v4_get_hash_protocol_manager") { ...@@ -127,9 +127,11 @@ static_library("v4_get_hash_protocol_manager") {
"v4_get_hash_protocol_manager.cc", "v4_get_hash_protocol_manager.cc",
"v4_get_hash_protocol_manager.h", "v4_get_hash_protocol_manager.h",
] ]
public_deps = [ ":safebrowsing_proto" ] public_deps = [
deps = [ ":safebrowsing_proto",
":util", ":util",
]
deps = [
":v4_protocol_manager_util", ":v4_protocol_manager_util",
"//base", "//base",
"//components/safe_browsing/core:features", "//components/safe_browsing/core:features",
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
// declarations instead of including more headers. If that is infeasible, adjust // declarations instead of including more headers. If that is infeasible, adjust
// the limit. For more info, see // the limit. For more info, see
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#pragma clang max_tokens_here 860000 #pragma clang max_tokens_here 880000
#include <utility> #include <utility>
......
...@@ -206,12 +206,14 @@ source_set("eg_test_support+eg2") { ...@@ -206,12 +206,14 @@ source_set("eg_test_support+eg2") {
"scoped_block_popups_pref.mm", "scoped_block_popups_pref.mm",
] ]
public_deps = [ ":chrome_egtest_bundle_main+eg2" ] public_deps = [
":chrome_egtest_bundle_main+eg2",
"//components/content_settings/core/common",
]
deps = [ deps = [
"//base", "//base",
"//base/test:test_support", "//base/test:test_support",
"//components/content_settings/core/common:common",
"//components/strings", "//components/strings",
"//components/sync/base", "//components/sync/base",
"//ios/chrome/app/strings", "//ios/chrome/app/strings",
......
...@@ -1766,6 +1766,7 @@ source_set("net_public_deps") { ...@@ -1766,6 +1766,7 @@ source_set("net_public_deps") {
public_deps = [ public_deps = [
":buildflags", ":buildflags",
":net_nqe_proto", ":net_nqe_proto",
"//base",
"//crypto", "//crypto",
"//crypto:platform", "//crypto:platform",
"//net/third_party/quiche:net_quic_proto", "//net/third_party/quiche:net_quic_proto",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment