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