1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/values.h"
6
7 #include <cmath>
8 #include <memory>
9 #include <optional>
10 #include <ostream>
11 #include <tuple>
12 #include <utility>
13
14 #include "base/bit_cast.h"
15 #include "base/check.h"
16 #include "base/check_op.h"
17 #include "base/containers/checked_iterators.h"
18 #include "base/containers/map_util.h"
19 #include "base/json/json_writer.h"
20 #include "base/logging.h"
21 #include "base/memory/ptr_util.h"
22 #include "base/notreached.h"
23 #include "base/ranges/algorithm.h"
24 #include "base/strings/string_util.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "base/trace_event/base_tracing.h"
27 #include "base/tracing_buildflags.h"
28 #include "base/types/to_address.h"
29 #include "third_party/abseil-cpp/absl/types/variant.h"
30
31 #if BUILDFLAG(ENABLE_BASE_TRACING)
32 #include "base/trace_event/memory_usage_estimator.h" // no-presubmit-check
33 #endif // BUILDFLAG(ENABLE_BASE_TRACING)
34
35 namespace base {
36
37 namespace {
38
39 const char* const kTypeNames[] = {"null", "boolean", "integer", "double",
40 "string", "binary", "dictionary", "list"};
41 static_assert(std::size(kTypeNames) ==
42 static_cast<size_t>(Value::Type::LIST) + 1,
43 "kTypeNames Has Wrong Size");
44
45 // Helper class to enumerate the path components from a StringPiece
46 // without performing heap allocations. Components are simply separated
47 // by single dots (e.g. "foo.bar.baz" -> ["foo", "bar", "baz"]).
48 //
49 // Usage example:
50 // PathSplitter splitter(some_path);
51 // while (splitter.HasNext()) {
52 // StringPiece component = splitter.Next();
53 // ...
54 // }
55 //
56 class PathSplitter {
57 public:
PathSplitter(StringPiece path)58 explicit PathSplitter(StringPiece path) : path_(path) {}
59
HasNext() const60 bool HasNext() const { return pos_ < path_.size(); }
61
Next()62 StringPiece Next() {
63 DCHECK(HasNext());
64 size_t start = pos_;
65 size_t pos = path_.find('.', start);
66 size_t end;
67 if (pos == path_.npos) {
68 end = path_.size();
69 pos_ = end;
70 } else {
71 end = pos;
72 pos_ = pos + 1;
73 }
74 return path_.substr(start, end - start);
75 }
76
77 private:
78 StringPiece path_;
79 size_t pos_ = 0;
80 };
81
DebugStringImpl(ValueView value)82 std::string DebugStringImpl(ValueView value) {
83 std::string json;
84 JSONWriter::WriteWithOptions(value, JSONWriter::OPTIONS_PRETTY_PRINT, &json);
85 return json;
86 }
87
88 } // namespace
89
90 // A helper used to provide templated functions for cloning to Value, and
91 // ValueView. This private class is used so the cloning method may have access
92 // to the special private constructors in Value, created specifically for
93 // cloning.
94 class Value::CloningHelper {
95 public:
96 // This set of overloads are used to unwrap the reference wrappers, which are
97 // presented when cloning a ValueView.
98 template <typename T>
UnwrapReference(std::reference_wrapper<const T> value)99 static const T& UnwrapReference(std::reference_wrapper<const T> value) {
100 return value.get();
101 }
102
103 template <typename T>
UnwrapReference(const T & value)104 static const T& UnwrapReference(const T& value) {
105 return value;
106 }
107
108 // Returns a new Value object using the contents of the |storage| variant.
109 template <typename Storage>
Clone(const Storage & storage)110 static Value Clone(const Storage& storage) {
111 return absl::visit(
112 [](const auto& member) {
113 const auto& value = UnwrapReference(member);
114 using T = std::decay_t<decltype(value)>;
115 if constexpr (std::is_same_v<T, Value::Dict> ||
116 std::is_same_v<T, Value::List>) {
117 return Value(value.Clone());
118 } else {
119 return Value(value);
120 }
121 },
122 storage);
123 }
124 };
125
126 // static
FromUniquePtrValue(std::unique_ptr<Value> val)127 Value Value::FromUniquePtrValue(std::unique_ptr<Value> val) {
128 return std::move(*val);
129 }
130
131 // static
ToUniquePtrValue(Value val)132 std::unique_ptr<Value> Value::ToUniquePtrValue(Value val) {
133 return std::make_unique<Value>(std::move(val));
134 }
135
136 Value::Value() noexcept = default;
137
138 Value::Value(Value&&) noexcept = default;
139
140 Value& Value::operator=(Value&&) noexcept = default;
141
Value(Type type)142 Value::Value(Type type) {
143 // Initialize with the default value.
144 switch (type) {
145 case Type::NONE:
146 return;
147
148 case Type::BOOLEAN:
149 data_.emplace<bool>(false);
150 return;
151 case Type::INTEGER:
152 data_.emplace<int>(0);
153 return;
154 case Type::DOUBLE:
155 data_.emplace<DoubleStorage>(0.0);
156 return;
157 case Type::STRING:
158 data_.emplace<std::string>();
159 return;
160 case Type::BINARY:
161 data_.emplace<BlobStorage>();
162 return;
163 case Type::DICT:
164 data_.emplace<Dict>();
165 return;
166 case Type::LIST:
167 data_.emplace<List>();
168 return;
169 }
170
171 CHECK(false);
172 }
173
Value(bool value)174 Value::Value(bool value) : data_(value) {}
175
Value(int value)176 Value::Value(int value) : data_(value) {}
177
Value(double value)178 Value::Value(double value)
179 : data_(absl::in_place_type_t<DoubleStorage>(), value) {}
180
Value(StringPiece value)181 Value::Value(StringPiece value) : Value(std::string(value)) {}
182
Value(StringPiece16 value)183 Value::Value(StringPiece16 value) : Value(UTF16ToUTF8(value)) {}
184
Value(const char * value)185 Value::Value(const char* value) : Value(std::string(value)) {}
186
Value(const char16_t * value)187 Value::Value(const char16_t* value) : Value(UTF16ToUTF8(value)) {}
188
Value(std::string && value)189 Value::Value(std::string&& value) noexcept : data_(std::move(value)) {
190 DCHECK(IsStringUTF8AllowingNoncharacters(GetString()));
191 }
192
Value(const std::vector<char> & value)193 Value::Value(const std::vector<char>& value)
194 : data_(absl::in_place_type_t<BlobStorage>(), value.begin(), value.end()) {}
195
Value(base::span<const uint8_t> value)196 Value::Value(base::span<const uint8_t> value)
197 : data_(absl::in_place_type_t<BlobStorage>(), value.size()) {
198 // This is 100x faster than using the "range" constructor for a 512k blob:
199 // crbug.com/1343636
200 ranges::copy(value, absl::get<BlobStorage>(data_).data());
201 }
202
Value(BlobStorage && value)203 Value::Value(BlobStorage&& value) noexcept : data_(std::move(value)) {}
204
Value(Dict && value)205 Value::Value(Dict&& value) noexcept : data_(std::move(value)) {}
206
Value(List && value)207 Value::Value(List&& value) noexcept : data_(std::move(value)) {}
208
Value(absl::monostate)209 Value::Value(absl::monostate) {}
210
Value(DoubleStorage storage)211 Value::Value(DoubleStorage storage) : data_(std::move(storage)) {}
212
DoubleStorage(double v)213 Value::DoubleStorage::DoubleStorage(double v) : v_(bit_cast<decltype(v_)>(v)) {
214 if (!std::isfinite(v)) {
215 NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) "
216 << "values cannot be represented in JSON";
217 v_ = bit_cast<decltype(v_)>(0.0);
218 }
219 }
220
Clone() const221 Value Value::Clone() const {
222 return CloningHelper::Clone(data_);
223 }
224
225 Value::~Value() = default;
226
227 // static
GetTypeName(Value::Type type)228 const char* Value::GetTypeName(Value::Type type) {
229 DCHECK_GE(static_cast<int>(type), 0);
230 DCHECK_LT(static_cast<size_t>(type), std::size(kTypeNames));
231 return kTypeNames[static_cast<size_t>(type)];
232 }
233
GetIfBool() const234 std::optional<bool> Value::GetIfBool() const {
235 return is_bool() ? std::make_optional(GetBool()) : std::nullopt;
236 }
237
GetIfInt() const238 std::optional<int> Value::GetIfInt() const {
239 return is_int() ? std::make_optional(GetInt()) : std::nullopt;
240 }
241
GetIfDouble() const242 std::optional<double> Value::GetIfDouble() const {
243 return (is_int() || is_double()) ? std::make_optional(GetDouble())
244 : std::nullopt;
245 }
246
GetIfString() const247 const std::string* Value::GetIfString() const {
248 return absl::get_if<std::string>(&data_);
249 }
250
GetIfString()251 std::string* Value::GetIfString() {
252 return absl::get_if<std::string>(&data_);
253 }
254
GetIfBlob() const255 const Value::BlobStorage* Value::GetIfBlob() const {
256 return absl::get_if<BlobStorage>(&data_);
257 }
258
GetIfDict() const259 const Value::Dict* Value::GetIfDict() const {
260 return absl::get_if<Dict>(&data_);
261 }
262
GetIfDict()263 Value::Dict* Value::GetIfDict() {
264 return absl::get_if<Dict>(&data_);
265 }
266
GetIfList() const267 const Value::List* Value::GetIfList() const {
268 return absl::get_if<List>(&data_);
269 }
270
GetIfList()271 Value::List* Value::GetIfList() {
272 return absl::get_if<List>(&data_);
273 }
274
GetBool() const275 bool Value::GetBool() const {
276 DCHECK(is_bool());
277 return absl::get<bool>(data_);
278 }
279
GetInt() const280 int Value::GetInt() const {
281 DCHECK(is_int());
282 return absl::get<int>(data_);
283 }
284
GetDouble() const285 double Value::GetDouble() const {
286 if (is_double()) {
287 return absl::get<DoubleStorage>(data_);
288 }
289 if (is_int()) {
290 return GetInt();
291 }
292 CHECK(false);
293 return 0.0;
294 }
295
GetString() const296 const std::string& Value::GetString() const {
297 DCHECK(is_string());
298 return absl::get<std::string>(data_);
299 }
300
GetString()301 std::string& Value::GetString() {
302 DCHECK(is_string());
303 return absl::get<std::string>(data_);
304 }
305
GetBlob() const306 const Value::BlobStorage& Value::GetBlob() const {
307 DCHECK(is_blob());
308 return absl::get<BlobStorage>(data_);
309 }
310
GetDict() const311 const Value::Dict& Value::GetDict() const {
312 DCHECK(is_dict());
313 return absl::get<Dict>(data_);
314 }
315
GetDict()316 Value::Dict& Value::GetDict() {
317 DCHECK(is_dict());
318 return absl::get<Dict>(data_);
319 }
320
GetList() const321 const Value::List& Value::GetList() const {
322 DCHECK(is_list());
323 return absl::get<List>(data_);
324 }
325
GetList()326 Value::List& Value::GetList() {
327 DCHECK(is_list());
328 return absl::get<List>(data_);
329 }
330
TakeString()331 std::string Value::TakeString() && {
332 return std::move(GetString());
333 }
334
TakeDict()335 Value::Dict Value::TakeDict() && {
336 return std::move(GetDict());
337 }
338
TakeList()339 Value::List Value::TakeList() && {
340 return std::move(GetList());
341 }
342
343 Value::Dict::Dict() = default;
344
345 Value::Dict::Dict(Dict&&) noexcept = default;
346
347 Value::Dict& Value::Dict::operator=(Dict&&) noexcept = default;
348
349 Value::Dict::~Dict() = default;
350
empty() const351 bool Value::Dict::empty() const {
352 return storage_.empty();
353 }
354
size() const355 size_t Value::Dict::size() const {
356 return storage_.size();
357 }
358
begin()359 Value::Dict::iterator Value::Dict::begin() {
360 return iterator(storage_.begin());
361 }
362
begin() const363 Value::Dict::const_iterator Value::Dict::begin() const {
364 return const_iterator(storage_.begin());
365 }
366
cbegin() const367 Value::Dict::const_iterator Value::Dict::cbegin() const {
368 return const_iterator(storage_.cbegin());
369 }
370
end()371 Value::Dict::iterator Value::Dict::end() {
372 return iterator(storage_.end());
373 }
374
end() const375 Value::Dict::const_iterator Value::Dict::end() const {
376 return const_iterator(storage_.end());
377 }
378
cend() const379 Value::Dict::const_iterator Value::Dict::cend() const {
380 return const_iterator(storage_.cend());
381 }
382
contains(base::StringPiece key) const383 bool Value::Dict::contains(base::StringPiece key) const {
384 DCHECK(IsStringUTF8AllowingNoncharacters(key));
385
386 return storage_.contains(key);
387 }
388
clear()389 void Value::Dict::clear() {
390 return storage_.clear();
391 }
392
erase(iterator pos)393 Value::Dict::iterator Value::Dict::erase(iterator pos) {
394 return iterator(storage_.erase(pos.GetUnderlyingIteratorDoNotUse()));
395 }
396
erase(const_iterator pos)397 Value::Dict::iterator Value::Dict::erase(const_iterator pos) {
398 return iterator(storage_.erase(pos.GetUnderlyingIteratorDoNotUse()));
399 }
400
Clone() const401 Value::Dict Value::Dict::Clone() const {
402 return Dict(storage_);
403 }
404
Merge(Dict dict)405 void Value::Dict::Merge(Dict dict) {
406 for (const auto [key, value] : dict) {
407 if (Dict* nested_dict = value.GetIfDict()) {
408 if (Dict* current_dict = FindDict(key)) {
409 // If `key` is a nested dictionary in this dictionary and the dictionary
410 // being merged, recursively merge the two dictionaries.
411 current_dict->Merge(std::move(*nested_dict));
412 continue;
413 }
414 }
415
416 // Otherwise, unconditionally set the value, overwriting any value that may
417 // already be associated with the key.
418 Set(key, std::move(value));
419 }
420 }
421
Find(StringPiece key) const422 const Value* Value::Dict::Find(StringPiece key) const {
423 DCHECK(IsStringUTF8AllowingNoncharacters(key));
424 return FindPtrOrNull(storage_, key);
425 }
426
Find(StringPiece key)427 Value* Value::Dict::Find(StringPiece key) {
428 return FindPtrOrNull(storage_, key);
429 }
430
FindBool(StringPiece key) const431 std::optional<bool> Value::Dict::FindBool(StringPiece key) const {
432 const Value* v = Find(key);
433 return v ? v->GetIfBool() : std::nullopt;
434 }
435
FindInt(StringPiece key) const436 std::optional<int> Value::Dict::FindInt(StringPiece key) const {
437 const Value* v = Find(key);
438 return v ? v->GetIfInt() : std::nullopt;
439 }
440
FindDouble(StringPiece key) const441 std::optional<double> Value::Dict::FindDouble(StringPiece key) const {
442 const Value* v = Find(key);
443 return v ? v->GetIfDouble() : std::nullopt;
444 }
445
FindString(StringPiece key) const446 const std::string* Value::Dict::FindString(StringPiece key) const {
447 const Value* v = Find(key);
448 return v ? v->GetIfString() : nullptr;
449 }
450
FindString(StringPiece key)451 std::string* Value::Dict::FindString(StringPiece key) {
452 Value* v = Find(key);
453 return v ? v->GetIfString() : nullptr;
454 }
455
FindBlob(StringPiece key) const456 const Value::BlobStorage* Value::Dict::FindBlob(StringPiece key) const {
457 const Value* v = Find(key);
458 return v ? v->GetIfBlob() : nullptr;
459 }
460
FindDict(StringPiece key) const461 const Value::Dict* Value::Dict::FindDict(StringPiece key) const {
462 const Value* v = Find(key);
463 return v ? v->GetIfDict() : nullptr;
464 }
465
FindDict(StringPiece key)466 Value::Dict* Value::Dict::FindDict(StringPiece key) {
467 Value* v = Find(key);
468 return v ? v->GetIfDict() : nullptr;
469 }
470
FindList(StringPiece key) const471 const Value::List* Value::Dict::FindList(StringPiece key) const {
472 const Value* v = Find(key);
473 return v ? v->GetIfList() : nullptr;
474 }
475
FindList(StringPiece key)476 Value::List* Value::Dict::FindList(StringPiece key) {
477 Value* v = Find(key);
478 return v ? v->GetIfList() : nullptr;
479 }
480
EnsureDict(StringPiece key)481 Value::Dict* Value::Dict::EnsureDict(StringPiece key) {
482 Value::Dict* dict = FindDict(key);
483 if (dict) {
484 return dict;
485 }
486 return &Set(key, base::Value::Dict())->GetDict();
487 }
488
EnsureList(StringPiece key)489 Value::List* Value::Dict::EnsureList(StringPiece key) {
490 Value::List* list = FindList(key);
491 if (list) {
492 return list;
493 }
494 return &Set(key, base::Value::List())->GetList();
495 }
496
Set(StringPiece key,Value && value)497 Value* Value::Dict::Set(StringPiece key, Value&& value) & {
498 DCHECK(IsStringUTF8AllowingNoncharacters(key));
499
500 auto wrapped_value = std::make_unique<Value>(std::move(value));
501 auto* raw_value = wrapped_value.get();
502 storage_.insert_or_assign(key, std::move(wrapped_value));
503 return raw_value;
504 }
505
Set(StringPiece key,bool value)506 Value* Value::Dict::Set(StringPiece key, bool value) & {
507 return Set(key, Value(value));
508 }
509
Set(StringPiece key,int value)510 Value* Value::Dict::Set(StringPiece key, int value) & {
511 return Set(key, Value(value));
512 }
513
Set(StringPiece key,double value)514 Value* Value::Dict::Set(StringPiece key, double value) & {
515 return Set(key, Value(value));
516 }
517
Set(StringPiece key,StringPiece value)518 Value* Value::Dict::Set(StringPiece key, StringPiece value) & {
519 return Set(key, Value(value));
520 }
521
Set(StringPiece key,StringPiece16 value)522 Value* Value::Dict::Set(StringPiece key, StringPiece16 value) & {
523 return Set(key, Value(value));
524 }
525
Set(StringPiece key,const char * value)526 Value* Value::Dict::Set(StringPiece key, const char* value) & {
527 return Set(key, Value(value));
528 }
529
Set(StringPiece key,const char16_t * value)530 Value* Value::Dict::Set(StringPiece key, const char16_t* value) & {
531 return Set(key, Value(value));
532 }
533
Set(StringPiece key,std::string && value)534 Value* Value::Dict::Set(StringPiece key, std::string&& value) & {
535 return Set(key, Value(std::move(value)));
536 }
537
Set(StringPiece key,BlobStorage && value)538 Value* Value::Dict::Set(StringPiece key, BlobStorage&& value) & {
539 return Set(key, Value(std::move(value)));
540 }
541
Set(StringPiece key,Dict && value)542 Value* Value::Dict::Set(StringPiece key, Dict&& value) & {
543 return Set(key, Value(std::move(value)));
544 }
545
Set(StringPiece key,List && value)546 Value* Value::Dict::Set(StringPiece key, List&& value) & {
547 return Set(key, Value(std::move(value)));
548 }
549
Set(StringPiece key,Value && value)550 Value::Dict&& Value::Dict::Set(StringPiece key, Value&& value) && {
551 DCHECK(IsStringUTF8AllowingNoncharacters(key));
552 storage_.insert_or_assign(key, std::make_unique<Value>(std::move(value)));
553 return std::move(*this);
554 }
555
Set(StringPiece key,bool value)556 Value::Dict&& Value::Dict::Set(StringPiece key, bool value) && {
557 return std::move(*this).Set(key, Value(value));
558 }
559
Set(StringPiece key,int value)560 Value::Dict&& Value::Dict::Set(StringPiece key, int value) && {
561 return std::move(*this).Set(key, Value(value));
562 }
563
Set(StringPiece key,double value)564 Value::Dict&& Value::Dict::Set(StringPiece key, double value) && {
565 return std::move(*this).Set(key, Value(value));
566 }
567
Set(StringPiece key,StringPiece value)568 Value::Dict&& Value::Dict::Set(StringPiece key, StringPiece value) && {
569 return std::move(*this).Set(key, Value(value));
570 }
571
Set(StringPiece key,StringPiece16 value)572 Value::Dict&& Value::Dict::Set(StringPiece key, StringPiece16 value) && {
573 return std::move(*this).Set(key, Value(value));
574 }
575
Set(StringPiece key,const char * value)576 Value::Dict&& Value::Dict::Set(StringPiece key, const char* value) && {
577 return std::move(*this).Set(key, Value(value));
578 }
579
Set(StringPiece key,const char16_t * value)580 Value::Dict&& Value::Dict::Set(StringPiece key, const char16_t* value) && {
581 return std::move(*this).Set(key, Value(value));
582 }
583
Set(StringPiece key,std::string && value)584 Value::Dict&& Value::Dict::Set(StringPiece key, std::string&& value) && {
585 return std::move(*this).Set(key, Value(std::move(value)));
586 }
587
Set(StringPiece key,BlobStorage && value)588 Value::Dict&& Value::Dict::Set(StringPiece key, BlobStorage&& value) && {
589 return std::move(*this).Set(key, Value(std::move(value)));
590 }
591
Set(StringPiece key,Dict && value)592 Value::Dict&& Value::Dict::Set(StringPiece key, Dict&& value) && {
593 return std::move(*this).Set(key, Value(std::move(value)));
594 }
595
Set(StringPiece key,List && value)596 Value::Dict&& Value::Dict::Set(StringPiece key, List&& value) && {
597 return std::move(*this).Set(key, Value(std::move(value)));
598 }
599
Remove(StringPiece key)600 bool Value::Dict::Remove(StringPiece key) {
601 DCHECK(IsStringUTF8AllowingNoncharacters(key));
602
603 return storage_.erase(key) > 0;
604 }
605
Extract(StringPiece key)606 std::optional<Value> Value::Dict::Extract(StringPiece key) {
607 DCHECK(IsStringUTF8AllowingNoncharacters(key));
608
609 auto it = storage_.find(key);
610 if (it == storage_.end()) {
611 return std::nullopt;
612 }
613 Value v = std::move(*it->second);
614 storage_.erase(it);
615 return v;
616 }
617
FindByDottedPath(StringPiece path) const618 const Value* Value::Dict::FindByDottedPath(StringPiece path) const {
619 DCHECK(!path.empty());
620 DCHECK(IsStringUTF8AllowingNoncharacters(path));
621
622 const Dict* current_dict = this;
623 const Value* current_value = nullptr;
624 PathSplitter splitter(path);
625 while (true) {
626 current_value = current_dict->Find(splitter.Next());
627 if (!splitter.HasNext()) {
628 return current_value;
629 }
630 if (!current_value) {
631 return nullptr;
632 }
633 current_dict = current_value->GetIfDict();
634 if (!current_dict) {
635 return nullptr;
636 }
637 }
638 }
639
FindByDottedPath(StringPiece path)640 Value* Value::Dict::FindByDottedPath(StringPiece path) {
641 return const_cast<Value*>(std::as_const(*this).FindByDottedPath(path));
642 }
643
FindBoolByDottedPath(StringPiece path) const644 std::optional<bool> Value::Dict::FindBoolByDottedPath(StringPiece path) const {
645 const Value* v = FindByDottedPath(path);
646 return v ? v->GetIfBool() : std::nullopt;
647 }
648
FindIntByDottedPath(StringPiece path) const649 std::optional<int> Value::Dict::FindIntByDottedPath(StringPiece path) const {
650 const Value* v = FindByDottedPath(path);
651 return v ? v->GetIfInt() : std::nullopt;
652 }
653
FindDoubleByDottedPath(StringPiece path) const654 std::optional<double> Value::Dict::FindDoubleByDottedPath(
655 StringPiece path) const {
656 const Value* v = FindByDottedPath(path);
657 return v ? v->GetIfDouble() : std::nullopt;
658 }
659
FindStringByDottedPath(StringPiece path) const660 const std::string* Value::Dict::FindStringByDottedPath(StringPiece path) const {
661 const Value* v = FindByDottedPath(path);
662 return v ? v->GetIfString() : nullptr;
663 }
664
FindStringByDottedPath(StringPiece path)665 std::string* Value::Dict::FindStringByDottedPath(StringPiece path) {
666 Value* v = FindByDottedPath(path);
667 return v ? v->GetIfString() : nullptr;
668 }
669
FindBlobByDottedPath(StringPiece path) const670 const Value::BlobStorage* Value::Dict::FindBlobByDottedPath(
671 StringPiece path) const {
672 const Value* v = FindByDottedPath(path);
673 return v ? v->GetIfBlob() : nullptr;
674 }
675
FindDictByDottedPath(StringPiece path) const676 const Value::Dict* Value::Dict::FindDictByDottedPath(StringPiece path) const {
677 const Value* v = FindByDottedPath(path);
678 return v ? v->GetIfDict() : nullptr;
679 }
680
FindDictByDottedPath(StringPiece path)681 Value::Dict* Value::Dict::FindDictByDottedPath(StringPiece path) {
682 Value* v = FindByDottedPath(path);
683 return v ? v->GetIfDict() : nullptr;
684 }
685
FindListByDottedPath(StringPiece path) const686 const Value::List* Value::Dict::FindListByDottedPath(StringPiece path) const {
687 const Value* v = FindByDottedPath(path);
688 return v ? v->GetIfList() : nullptr;
689 }
690
FindListByDottedPath(StringPiece path)691 Value::List* Value::Dict::FindListByDottedPath(StringPiece path) {
692 Value* v = FindByDottedPath(path);
693 return v ? v->GetIfList() : nullptr;
694 }
695
SetByDottedPath(StringPiece path,Value && value)696 Value* Value::Dict::SetByDottedPath(StringPiece path, Value&& value) & {
697 DCHECK(!path.empty());
698 DCHECK(IsStringUTF8AllowingNoncharacters(path));
699
700 Dict* current_dict = this;
701 Value* current_value = nullptr;
702 PathSplitter splitter(path);
703 while (true) {
704 StringPiece next_key = splitter.Next();
705 if (!splitter.HasNext()) {
706 return current_dict->Set(next_key, std::move(value));
707 }
708 // This could be clever to avoid a double-lookup via use of lower_bound(),
709 // but for now, just implement it the most straightforward way.
710 current_value = current_dict->Find(next_key);
711 if (current_value) {
712 // Unlike the legacy DictionaryValue API, encountering an intermediate
713 // node that is not a `Value::Type::DICT` is an error.
714 current_dict = current_value->GetIfDict();
715 if (!current_dict) {
716 return nullptr;
717 }
718 } else {
719 current_dict = ¤t_dict->Set(next_key, Dict())->GetDict();
720 }
721 }
722 }
723
SetByDottedPath(StringPiece path,bool value)724 Value* Value::Dict::SetByDottedPath(StringPiece path, bool value) & {
725 return SetByDottedPath(path, Value(value));
726 }
727
SetByDottedPath(StringPiece path,int value)728 Value* Value::Dict::SetByDottedPath(StringPiece path, int value) & {
729 return SetByDottedPath(path, Value(value));
730 }
731
SetByDottedPath(StringPiece path,double value)732 Value* Value::Dict::SetByDottedPath(StringPiece path, double value) & {
733 return SetByDottedPath(path, Value(value));
734 }
735
SetByDottedPath(StringPiece path,StringPiece value)736 Value* Value::Dict::SetByDottedPath(StringPiece path, StringPiece value) & {
737 return SetByDottedPath(path, Value(value));
738 }
739
SetByDottedPath(StringPiece path,StringPiece16 value)740 Value* Value::Dict::SetByDottedPath(StringPiece path, StringPiece16 value) & {
741 return SetByDottedPath(path, Value(value));
742 }
743
SetByDottedPath(StringPiece path,const char * value)744 Value* Value::Dict::SetByDottedPath(StringPiece path, const char* value) & {
745 return SetByDottedPath(path, Value(value));
746 }
747
SetByDottedPath(StringPiece path,const char16_t * value)748 Value* Value::Dict::SetByDottedPath(StringPiece path, const char16_t* value) & {
749 return SetByDottedPath(path, Value(value));
750 }
751
SetByDottedPath(StringPiece path,std::string && value)752 Value* Value::Dict::SetByDottedPath(StringPiece path, std::string&& value) & {
753 return SetByDottedPath(path, Value(std::move(value)));
754 }
755
SetByDottedPath(StringPiece path,BlobStorage && value)756 Value* Value::Dict::SetByDottedPath(StringPiece path, BlobStorage&& value) & {
757 return SetByDottedPath(path, Value(std::move(value)));
758 }
759
SetByDottedPath(StringPiece path,Dict && value)760 Value* Value::Dict::SetByDottedPath(StringPiece path, Dict&& value) & {
761 return SetByDottedPath(path, Value(std::move(value)));
762 }
763
SetByDottedPath(StringPiece path,List && value)764 Value* Value::Dict::SetByDottedPath(StringPiece path, List&& value) & {
765 return SetByDottedPath(path, Value(std::move(value)));
766 }
767
RemoveByDottedPath(StringPiece path)768 bool Value::Dict::RemoveByDottedPath(StringPiece path) {
769 return ExtractByDottedPath(path).has_value();
770 }
771
SetByDottedPath(StringPiece path,Value && value)772 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path, Value&& value) && {
773 SetByDottedPath(path, std::move(value));
774 return std::move(*this);
775 }
776
SetByDottedPath(StringPiece path,bool value)777 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path, bool value) && {
778 SetByDottedPath(path, Value(value));
779 return std::move(*this);
780 }
781
SetByDottedPath(StringPiece path,int value)782 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path, int value) && {
783 SetByDottedPath(path, Value(value));
784 return std::move(*this);
785 }
786
SetByDottedPath(StringPiece path,double value)787 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path, double value) && {
788 SetByDottedPath(path, Value(value));
789 return std::move(*this);
790 }
791
SetByDottedPath(StringPiece path,StringPiece value)792 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path,
793 StringPiece value) && {
794 SetByDottedPath(path, Value(value));
795 return std::move(*this);
796 }
797
SetByDottedPath(StringPiece path,StringPiece16 value)798 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path,
799 StringPiece16 value) && {
800 SetByDottedPath(path, Value(value));
801 return std::move(*this);
802 }
803
SetByDottedPath(StringPiece path,const char * value)804 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path,
805 const char* value) && {
806 SetByDottedPath(path, Value(value));
807 return std::move(*this);
808 }
809
SetByDottedPath(StringPiece path,const char16_t * value)810 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path,
811 const char16_t* value) && {
812 SetByDottedPath(path, Value(value));
813 return std::move(*this);
814 }
815
SetByDottedPath(StringPiece path,std::string && value)816 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path,
817 std::string&& value) && {
818 SetByDottedPath(path, Value(std::move(value)));
819 return std::move(*this);
820 }
821
SetByDottedPath(StringPiece path,BlobStorage && value)822 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path,
823 BlobStorage&& value) && {
824 SetByDottedPath(path, Value(std::move(value)));
825 return std::move(*this);
826 }
827
SetByDottedPath(StringPiece path,Dict && value)828 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path, Dict&& value) && {
829 SetByDottedPath(path, Value(std::move(value)));
830 return std::move(*this);
831 }
832
SetByDottedPath(StringPiece path,List && value)833 Value::Dict&& Value::Dict::SetByDottedPath(StringPiece path, List&& value) && {
834 SetByDottedPath(path, Value(std::move(value)));
835 return std::move(*this);
836 }
837
ExtractByDottedPath(StringPiece path)838 std::optional<Value> Value::Dict::ExtractByDottedPath(StringPiece path) {
839 DCHECK(!path.empty());
840 DCHECK(IsStringUTF8AllowingNoncharacters(path));
841
842 // Use recursion instead of PathSplitter here, as it simplifies code for
843 // removing dictionaries that become empty if a value matching `path` is
844 // extracted.
845 size_t dot_index = path.find('.');
846 if (dot_index == StringPiece::npos) {
847 return Extract(path);
848 }
849 // This could be clever to avoid a double-lookup by using storage_ directly,
850 // but for now, just implement it in the most straightforward way.
851 StringPiece next_key = path.substr(0, dot_index);
852 auto* next_dict = FindDict(next_key);
853 if (!next_dict) {
854 return std::nullopt;
855 }
856 std::optional<Value> extracted =
857 next_dict->ExtractByDottedPath(path.substr(dot_index + 1));
858 if (extracted && next_dict->empty()) {
859 Remove(next_key);
860 }
861 return extracted;
862 }
863
EstimateMemoryUsage() const864 size_t Value::Dict::EstimateMemoryUsage() const {
865 #if BUILDFLAG(ENABLE_BASE_TRACING)
866 return base::trace_event::EstimateMemoryUsage(storage_);
867 #else // BUILDFLAG(ENABLE_BASE_TRACING)
868 return 0;
869 #endif // BUILDFLAG(ENABLE_BASE_TRACING)
870 }
871
DebugString() const872 std::string Value::Dict::DebugString() const {
873 return DebugStringImpl(*this);
874 }
875
876 #if BUILDFLAG(ENABLE_BASE_TRACING)
WriteIntoTrace(perfetto::TracedValue context) const877 void Value::Dict::WriteIntoTrace(perfetto::TracedValue context) const {
878 perfetto::TracedDictionary dict = std::move(context).WriteDictionary();
879 for (auto kv : *this) {
880 dict.Add(perfetto::DynamicString(kv.first), kv.second);
881 }
882 }
883 #endif // BUILDFLAG(ENABLE_BASE_TRACING)
884
Dict(const flat_map<std::string,std::unique_ptr<Value>> & storage)885 Value::Dict::Dict(
886 const flat_map<std::string, std::unique_ptr<Value>>& storage) {
887 storage_.reserve(storage.size());
888 for (const auto& [key, value] : storage) {
889 Set(key, value->Clone());
890 }
891 }
892
operator ==(const Value::Dict & lhs,const Value::Dict & rhs)893 bool operator==(const Value::Dict& lhs, const Value::Dict& rhs) {
894 auto deref_2nd = [](const auto& p) { return std::tie(p.first, *p.second); };
895 return ranges::equal(lhs.storage_, rhs.storage_, {}, deref_2nd, deref_2nd);
896 }
897
operator !=(const Value::Dict & lhs,const Value::Dict & rhs)898 bool operator!=(const Value::Dict& lhs, const Value::Dict& rhs) {
899 return !(lhs == rhs);
900 }
901
operator <(const Value::Dict & lhs,const Value::Dict & rhs)902 bool operator<(const Value::Dict& lhs, const Value::Dict& rhs) {
903 auto deref_2nd = [](const auto& p) { return std::tie(p.first, *p.second); };
904 return ranges::lexicographical_compare(lhs.storage_, rhs.storage_, {},
905 deref_2nd, deref_2nd);
906 }
907
operator >(const Value::Dict & lhs,const Value::Dict & rhs)908 bool operator>(const Value::Dict& lhs, const Value::Dict& rhs) {
909 return rhs < lhs;
910 }
911
operator <=(const Value::Dict & lhs,const Value::Dict & rhs)912 bool operator<=(const Value::Dict& lhs, const Value::Dict& rhs) {
913 return !(rhs < lhs);
914 }
915
operator >=(const Value::Dict & lhs,const Value::Dict & rhs)916 bool operator>=(const Value::Dict& lhs, const Value::Dict& rhs) {
917 return !(lhs < rhs);
918 }
919
920 // static
with_capacity(size_t capacity)921 Value::List Value::List::with_capacity(size_t capacity) {
922 Value::List result;
923 result.reserve(capacity);
924 return result;
925 }
926
927 Value::List::List() = default;
928
929 Value::List::List(List&&) noexcept = default;
930
931 Value::List& Value::List::operator=(List&&) noexcept = default;
932
933 Value::List::~List() = default;
934
empty() const935 bool Value::List::empty() const {
936 return storage_.empty();
937 }
938
size() const939 size_t Value::List::size() const {
940 return storage_.size();
941 }
942
begin()943 Value::List::iterator Value::List::begin() {
944 return iterator(base::to_address(storage_.begin()),
945 base::to_address(storage_.end()));
946 }
947
begin() const948 Value::List::const_iterator Value::List::begin() const {
949 return const_iterator(base::to_address(storage_.begin()),
950 base::to_address(storage_.end()));
951 }
952
cbegin() const953 Value::List::const_iterator Value::List::cbegin() const {
954 return const_iterator(base::to_address(storage_.cbegin()),
955 base::to_address(storage_.cend()));
956 }
957
end()958 Value::List::iterator Value::List::end() {
959 return iterator(base::to_address(storage_.begin()),
960 base::to_address(storage_.end()),
961 base::to_address(storage_.end()));
962 }
963
end() const964 Value::List::const_iterator Value::List::end() const {
965 return const_iterator(base::to_address(storage_.begin()),
966 base::to_address(storage_.end()),
967 base::to_address(storage_.end()));
968 }
969
cend() const970 Value::List::const_iterator Value::List::cend() const {
971 return const_iterator(base::to_address(storage_.cbegin()),
972 base::to_address(storage_.cend()),
973 base::to_address(storage_.cend()));
974 }
975
rend()976 Value::List::reverse_iterator Value::List::rend() {
977 return reverse_iterator(begin());
978 }
979
rend() const980 Value::List::const_reverse_iterator Value::List::rend() const {
981 return const_reverse_iterator(begin());
982 }
983
rbegin()984 Value::List::reverse_iterator Value::List::rbegin() {
985 return reverse_iterator(end());
986 }
987
rbegin() const988 Value::List::const_reverse_iterator Value::List::rbegin() const {
989 return const_reverse_iterator(end());
990 }
991
front() const992 const Value& Value::List::front() const {
993 CHECK(!storage_.empty());
994 return storage_.front();
995 }
996
front()997 Value& Value::List::front() {
998 CHECK(!storage_.empty());
999 return storage_.front();
1000 }
1001
back() const1002 const Value& Value::List::back() const {
1003 CHECK(!storage_.empty());
1004 return storage_.back();
1005 }
1006
back()1007 Value& Value::List::back() {
1008 CHECK(!storage_.empty());
1009 return storage_.back();
1010 }
1011
reserve(size_t capacity)1012 void Value::List::reserve(size_t capacity) {
1013 storage_.reserve(capacity);
1014 }
1015
resize(size_t new_size)1016 void Value::List::resize(size_t new_size) {
1017 storage_.resize(new_size);
1018 }
1019
operator [](size_t index) const1020 const Value& Value::List::operator[](size_t index) const {
1021 CHECK_LT(index, storage_.size());
1022 return storage_[index];
1023 }
1024
operator [](size_t index)1025 Value& Value::List::operator[](size_t index) {
1026 CHECK_LT(index, storage_.size());
1027 return storage_[index];
1028 }
1029
clear()1030 void Value::List::clear() {
1031 storage_.clear();
1032 }
1033
erase(iterator pos)1034 Value::List::iterator Value::List::erase(iterator pos) {
1035 auto next_it = storage_.erase(storage_.begin() + (pos - begin()));
1036 return iterator(base::to_address(storage_.begin()), base::to_address(next_it),
1037 base::to_address(storage_.end()));
1038 }
1039
erase(const_iterator pos)1040 Value::List::const_iterator Value::List::erase(const_iterator pos) {
1041 auto next_it = storage_.erase(storage_.begin() + (pos - begin()));
1042 return const_iterator(base::to_address(storage_.begin()),
1043 base::to_address(next_it),
1044 base::to_address(storage_.end()));
1045 }
1046
erase(iterator first,iterator last)1047 Value::List::iterator Value::List::erase(iterator first, iterator last) {
1048 auto next_it = storage_.erase(storage_.begin() + (first - begin()),
1049 storage_.begin() + (last - begin()));
1050 return iterator(base::to_address(storage_.begin()), base::to_address(next_it),
1051 base::to_address(storage_.end()));
1052 }
1053
erase(const_iterator first,const_iterator last)1054 Value::List::const_iterator Value::List::erase(const_iterator first,
1055 const_iterator last) {
1056 auto next_it = storage_.erase(storage_.begin() + (first - begin()),
1057 storage_.begin() + (last - begin()));
1058 return const_iterator(base::to_address(storage_.begin()),
1059 base::to_address(next_it),
1060 base::to_address(storage_.end()));
1061 }
1062
Clone() const1063 Value::List Value::List::Clone() const {
1064 return List(storage_);
1065 }
1066
Append(Value && value)1067 void Value::List::Append(Value&& value) & {
1068 storage_.emplace_back(std::move(value));
1069 }
1070
Append(bool value)1071 void Value::List::Append(bool value) & {
1072 storage_.emplace_back(value);
1073 }
1074
Append(int value)1075 void Value::List::Append(int value) & {
1076 storage_.emplace_back(value);
1077 }
1078
Append(double value)1079 void Value::List::Append(double value) & {
1080 storage_.emplace_back(value);
1081 }
1082
Append(StringPiece value)1083 void Value::List::Append(StringPiece value) & {
1084 Append(Value(value));
1085 }
1086
Append(StringPiece16 value)1087 void Value::List::Append(StringPiece16 value) & {
1088 storage_.emplace_back(value);
1089 }
1090
Append(const char * value)1091 void Value::List::Append(const char* value) & {
1092 storage_.emplace_back(value);
1093 }
1094
Append(const char16_t * value)1095 void Value::List::Append(const char16_t* value) & {
1096 storage_.emplace_back(value);
1097 }
1098
Append(std::string && value)1099 void Value::List::Append(std::string&& value) & {
1100 storage_.emplace_back(std::move(value));
1101 }
1102
Append(BlobStorage && value)1103 void Value::List::Append(BlobStorage&& value) & {
1104 storage_.emplace_back(std::move(value));
1105 }
1106
Append(Dict && value)1107 void Value::List::Append(Dict&& value) & {
1108 storage_.emplace_back(std::move(value));
1109 }
1110
Append(List && value)1111 void Value::List::Append(List&& value) & {
1112 storage_.emplace_back(std::move(value));
1113 }
1114
Append(Value && value)1115 Value::List&& Value::List::Append(Value&& value) && {
1116 storage_.emplace_back(std::move(value));
1117 return std::move(*this);
1118 }
1119
Append(bool value)1120 Value::List&& Value::List::Append(bool value) && {
1121 storage_.emplace_back(value);
1122 return std::move(*this);
1123 }
1124
Append(int value)1125 Value::List&& Value::List::Append(int value) && {
1126 storage_.emplace_back(value);
1127 return std::move(*this);
1128 }
1129
Append(double value)1130 Value::List&& Value::List::Append(double value) && {
1131 storage_.emplace_back(value);
1132 return std::move(*this);
1133 }
1134
Append(StringPiece value)1135 Value::List&& Value::List::Append(StringPiece value) && {
1136 Append(Value(value));
1137 return std::move(*this);
1138 }
1139
Append(StringPiece16 value)1140 Value::List&& Value::List::Append(StringPiece16 value) && {
1141 storage_.emplace_back(value);
1142 return std::move(*this);
1143 }
1144
Append(const char * value)1145 Value::List&& Value::List::Append(const char* value) && {
1146 storage_.emplace_back(value);
1147 return std::move(*this);
1148 }
1149
Append(const char16_t * value)1150 Value::List&& Value::List::Append(const char16_t* value) && {
1151 storage_.emplace_back(value);
1152 return std::move(*this);
1153 }
1154
Append(std::string && value)1155 Value::List&& Value::List::Append(std::string&& value) && {
1156 storage_.emplace_back(std::move(value));
1157 return std::move(*this);
1158 }
1159
Append(BlobStorage && value)1160 Value::List&& Value::List::Append(BlobStorage&& value) && {
1161 storage_.emplace_back(std::move(value));
1162 return std::move(*this);
1163 }
1164
Append(Dict && value)1165 Value::List&& Value::List::Append(Dict&& value) && {
1166 storage_.emplace_back(std::move(value));
1167 return std::move(*this);
1168 }
1169
Append(List && value)1170 Value::List&& Value::List::Append(List&& value) && {
1171 storage_.emplace_back(std::move(value));
1172 return std::move(*this);
1173 }
1174
Insert(const_iterator pos,Value && value)1175 Value::List::iterator Value::List::Insert(const_iterator pos, Value&& value) {
1176 auto inserted_it =
1177 storage_.insert(storage_.begin() + (pos - begin()), std::move(value));
1178 return iterator(base::to_address(storage_.begin()),
1179 base::to_address(inserted_it),
1180 base::to_address(storage_.end()));
1181 }
1182
EraseValue(const Value & value)1183 size_t Value::List::EraseValue(const Value& value) {
1184 return std::erase(storage_, value);
1185 }
1186
EstimateMemoryUsage() const1187 size_t Value::List::EstimateMemoryUsage() const {
1188 #if BUILDFLAG(ENABLE_BASE_TRACING)
1189 return base::trace_event::EstimateMemoryUsage(storage_);
1190 #else // BUILDFLAG(ENABLE_BASE_TRACING)
1191 return 0;
1192 #endif // BUILDFLAG(ENABLE_BASE_TRACING)
1193 }
1194
DebugString() const1195 std::string Value::List::DebugString() const {
1196 return DebugStringImpl(*this);
1197 }
1198
1199 #if BUILDFLAG(ENABLE_BASE_TRACING)
WriteIntoTrace(perfetto::TracedValue context) const1200 void Value::List::WriteIntoTrace(perfetto::TracedValue context) const {
1201 perfetto::TracedArray array = std::move(context).WriteArray();
1202 for (const auto& item : *this) {
1203 array.Append(item);
1204 }
1205 }
1206 #endif // BUILDFLAG(ENABLE_BASE_TRACING)
1207
List(const std::vector<Value> & storage)1208 Value::List::List(const std::vector<Value>& storage) {
1209 storage_.reserve(storage.size());
1210 for (const auto& value : storage) {
1211 storage_.push_back(value.Clone());
1212 }
1213 }
1214
operator ==(const Value::List & lhs,const Value::List & rhs)1215 bool operator==(const Value::List& lhs, const Value::List& rhs) {
1216 return lhs.storage_ == rhs.storage_;
1217 }
1218
operator !=(const Value::List & lhs,const Value::List & rhs)1219 bool operator!=(const Value::List& lhs, const Value::List& rhs) {
1220 return !(lhs == rhs);
1221 }
1222
operator <(const Value::List & lhs,const Value::List & rhs)1223 bool operator<(const Value::List& lhs, const Value::List& rhs) {
1224 return lhs.storage_ < rhs.storage_;
1225 }
1226
operator >(const Value::List & lhs,const Value::List & rhs)1227 bool operator>(const Value::List& lhs, const Value::List& rhs) {
1228 return rhs < lhs;
1229 }
1230
operator <=(const Value::List & lhs,const Value::List & rhs)1231 bool operator<=(const Value::List& lhs, const Value::List& rhs) {
1232 return !(rhs < lhs);
1233 }
1234
operator >=(const Value::List & lhs,const Value::List & rhs)1235 bool operator>=(const Value::List& lhs, const Value::List& rhs) {
1236 return !(lhs < rhs);
1237 }
1238
operator ==(const Value & lhs,const Value & rhs)1239 bool operator==(const Value& lhs, const Value& rhs) {
1240 return lhs.data_ == rhs.data_;
1241 }
1242
operator !=(const Value & lhs,const Value & rhs)1243 bool operator!=(const Value& lhs, const Value& rhs) {
1244 return !(lhs == rhs);
1245 }
1246
operator <(const Value & lhs,const Value & rhs)1247 bool operator<(const Value& lhs, const Value& rhs) {
1248 return lhs.data_ < rhs.data_;
1249 }
1250
operator >(const Value & lhs,const Value & rhs)1251 bool operator>(const Value& lhs, const Value& rhs) {
1252 return rhs < lhs;
1253 }
1254
operator <=(const Value & lhs,const Value & rhs)1255 bool operator<=(const Value& lhs, const Value& rhs) {
1256 return !(rhs < lhs);
1257 }
1258
operator >=(const Value & lhs,const Value & rhs)1259 bool operator>=(const Value& lhs, const Value& rhs) {
1260 return !(lhs < rhs);
1261 }
1262
operator ==(const Value & lhs,bool rhs)1263 bool operator==(const Value& lhs, bool rhs) {
1264 return lhs.is_bool() && lhs.GetBool() == rhs;
1265 }
1266
operator ==(const Value & lhs,int rhs)1267 bool operator==(const Value& lhs, int rhs) {
1268 return lhs.is_int() && lhs.GetInt() == rhs;
1269 }
1270
operator ==(const Value & lhs,double rhs)1271 bool operator==(const Value& lhs, double rhs) {
1272 return lhs.is_double() && lhs.GetDouble() == rhs;
1273 }
1274
operator ==(const Value & lhs,StringPiece rhs)1275 bool operator==(const Value& lhs, StringPiece rhs) {
1276 return lhs.is_string() && lhs.GetString() == rhs;
1277 }
1278
operator ==(const Value & lhs,const Value::Dict & rhs)1279 bool operator==(const Value& lhs, const Value::Dict& rhs) {
1280 return lhs.is_dict() && lhs.GetDict() == rhs;
1281 }
1282
operator ==(const Value & lhs,const Value::List & rhs)1283 bool operator==(const Value& lhs, const Value::List& rhs) {
1284 return lhs.is_list() && lhs.GetList() == rhs;
1285 }
1286
EstimateMemoryUsage() const1287 size_t Value::EstimateMemoryUsage() const {
1288 switch (type()) {
1289 #if BUILDFLAG(ENABLE_BASE_TRACING)
1290 case Type::STRING:
1291 return base::trace_event::EstimateMemoryUsage(GetString());
1292 case Type::BINARY:
1293 return base::trace_event::EstimateMemoryUsage(GetBlob());
1294 case Type::DICT:
1295 return GetDict().EstimateMemoryUsage();
1296 case Type::LIST:
1297 return GetList().EstimateMemoryUsage();
1298 #endif // BUILDFLAG(ENABLE_BASE_TRACING)
1299 default:
1300 return 0;
1301 }
1302 }
1303
DebugString() const1304 std::string Value::DebugString() const {
1305 return DebugStringImpl(*this);
1306 }
1307
1308 #if BUILDFLAG(ENABLE_BASE_TRACING)
WriteIntoTrace(perfetto::TracedValue context) const1309 void Value::WriteIntoTrace(perfetto::TracedValue context) const {
1310 Visit([&](const auto& member) {
1311 using T = std::decay_t<decltype(member)>;
1312 if constexpr (std::is_same_v<T, absl::monostate>) {
1313 std::move(context).WriteString("<none>");
1314 } else if constexpr (std::is_same_v<T, bool>) {
1315 std::move(context).WriteBoolean(member);
1316 } else if constexpr (std::is_same_v<T, int>) {
1317 std::move(context).WriteInt64(member);
1318 } else if constexpr (std::is_same_v<T, DoubleStorage>) {
1319 std::move(context).WriteDouble(member);
1320 } else if constexpr (std::is_same_v<T, std::string>) {
1321 std::move(context).WriteString(member);
1322 } else if constexpr (std::is_same_v<T, BlobStorage>) {
1323 std::move(context).WriteString("<binary data not supported>");
1324 } else if constexpr (std::is_same_v<T, Dict>) {
1325 member.WriteIntoTrace(std::move(context));
1326 } else if constexpr (std::is_same_v<T, List>) {
1327 member.WriteIntoTrace(std::move(context));
1328 }
1329 });
1330 }
1331 #endif // BUILDFLAG(ENABLE_BASE_TRACING)
1332
ValueView(const Value & value)1333 ValueView::ValueView(const Value& value)
1334 : data_view_(
1335 value.Visit([](const auto& member) { return ViewType(member); })) {}
1336
ToValue() const1337 Value ValueView::ToValue() const {
1338 return Value::CloningHelper::Clone(data_view_);
1339 }
1340
1341 ValueSerializer::~ValueSerializer() = default;
1342
1343 ValueDeserializer::~ValueDeserializer() = default;
1344
operator <<(std::ostream & out,const Value & value)1345 std::ostream& operator<<(std::ostream& out, const Value& value) {
1346 return out << value.DebugString();
1347 }
1348
operator <<(std::ostream & out,const Value::Dict & dict)1349 std::ostream& operator<<(std::ostream& out, const Value::Dict& dict) {
1350 return out << dict.DebugString();
1351 }
1352
operator <<(std::ostream & out,const Value::List & list)1353 std::ostream& operator<<(std::ostream& out, const Value::List& list) {
1354 return out << list.DebugString();
1355 }
1356
operator <<(std::ostream & out,const Value::Type & type)1357 std::ostream& operator<<(std::ostream& out, const Value::Type& type) {
1358 if (static_cast<int>(type) < 0 ||
1359 static_cast<size_t>(type) >= std::size(kTypeNames)) {
1360 return out << "Invalid Type (index = " << static_cast<int>(type) << ")";
1361 }
1362 return out << Value::GetTypeName(type);
1363 }
1364
1365 } // namespace base
1366