• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <ostream>
9 #include <tuple>
10 #include <utility>
11 
12 #include "base/bit_cast.h"
13 #include "base/check.h"
14 #include "base/check_op.h"
15 #include "base/containers/checked_iterators.h"
16 #include "base/containers/cxx20_erase_vector.h"
17 #include "base/cxx17_backports.h"
18 #include "base/cxx20_to_address.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 "third_party/abseil-cpp/absl/types/optional.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 absl::optional<bool> Value::GetIfBool() const {
235   return is_bool() ? absl::make_optional(GetBool()) : absl::nullopt;
236 }
237 
GetIfInt() const238 absl::optional<int> Value::GetIfInt() const {
239   return is_int() ? absl::make_optional(GetInt()) : absl::nullopt;
240 }
241 
GetIfDouble() const242 absl::optional<double> Value::GetIfDouble() const {
243   return (is_int() || is_double()) ? absl::make_optional(GetDouble())
244                                    : absl::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 
425   auto it = storage_.find(key);
426   return it != storage_.end() ? it->second.get() : nullptr;
427 }
428 
Find(StringPiece key)429 Value* Value::Dict::Find(StringPiece key) {
430   auto it = storage_.find(key);
431   return it != storage_.end() ? it->second.get() : nullptr;
432 }
433 
FindBool(StringPiece key) const434 absl::optional<bool> Value::Dict::FindBool(StringPiece key) const {
435   const Value* v = Find(key);
436   return v ? v->GetIfBool() : absl::nullopt;
437 }
438 
FindInt(StringPiece key) const439 absl::optional<int> Value::Dict::FindInt(StringPiece key) const {
440   const Value* v = Find(key);
441   return v ? v->GetIfInt() : absl::nullopt;
442 }
443 
FindDouble(StringPiece key) const444 absl::optional<double> Value::Dict::FindDouble(StringPiece key) const {
445   const Value* v = Find(key);
446   return v ? v->GetIfDouble() : absl::nullopt;
447 }
448 
FindString(StringPiece key) const449 const std::string* Value::Dict::FindString(StringPiece key) const {
450   const Value* v = Find(key);
451   return v ? v->GetIfString() : nullptr;
452 }
453 
FindString(StringPiece key)454 std::string* Value::Dict::FindString(StringPiece key) {
455   Value* v = Find(key);
456   return v ? v->GetIfString() : nullptr;
457 }
458 
FindBlob(StringPiece key) const459 const Value::BlobStorage* Value::Dict::FindBlob(StringPiece key) const {
460   const Value* v = Find(key);
461   return v ? v->GetIfBlob() : nullptr;
462 }
463 
FindDict(StringPiece key) const464 const Value::Dict* Value::Dict::FindDict(StringPiece key) const {
465   const Value* v = Find(key);
466   return v ? v->GetIfDict() : nullptr;
467 }
468 
FindDict(StringPiece key)469 Value::Dict* Value::Dict::FindDict(StringPiece key) {
470   Value* v = Find(key);
471   return v ? v->GetIfDict() : nullptr;
472 }
473 
FindList(StringPiece key) const474 const Value::List* Value::Dict::FindList(StringPiece key) const {
475   const Value* v = Find(key);
476   return v ? v->GetIfList() : nullptr;
477 }
478 
FindList(StringPiece key)479 Value::List* Value::Dict::FindList(StringPiece key) {
480   Value* v = Find(key);
481   return v ? v->GetIfList() : nullptr;
482 }
483 
EnsureDict(StringPiece key)484 Value::Dict* Value::Dict::EnsureDict(StringPiece key) {
485   Value::Dict* dict = FindDict(key);
486   if (dict) {
487     return dict;
488   }
489   return &Set(key, base::Value::Dict())->GetDict();
490 }
491 
EnsureList(StringPiece key)492 Value::List* Value::Dict::EnsureList(StringPiece key) {
493   Value::List* list = FindList(key);
494   if (list) {
495     return list;
496   }
497   return &Set(key, base::Value::List())->GetList();
498 }
499 
Set(StringPiece key,Value && value)500 Value* Value::Dict::Set(StringPiece key, Value&& value) & {
501   DCHECK(IsStringUTF8AllowingNoncharacters(key));
502 
503   auto wrapped_value = std::make_unique<Value>(std::move(value));
504   auto* raw_value = wrapped_value.get();
505   storage_.insert_or_assign(key, std::move(wrapped_value));
506   return raw_value;
507 }
508 
Set(StringPiece key,bool value)509 Value* Value::Dict::Set(StringPiece key, bool value) & {
510   return Set(key, Value(value));
511 }
512 
Set(StringPiece key,int value)513 Value* Value::Dict::Set(StringPiece key, int value) & {
514   return Set(key, Value(value));
515 }
516 
Set(StringPiece key,double value)517 Value* Value::Dict::Set(StringPiece key, double value) & {
518   return Set(key, Value(value));
519 }
520 
Set(StringPiece key,StringPiece value)521 Value* Value::Dict::Set(StringPiece key, StringPiece value) & {
522   return Set(key, Value(value));
523 }
524 
Set(StringPiece key,StringPiece16 value)525 Value* Value::Dict::Set(StringPiece key, StringPiece16 value) & {
526   return Set(key, Value(value));
527 }
528 
Set(StringPiece key,const char * value)529 Value* Value::Dict::Set(StringPiece key, const char* value) & {
530   return Set(key, Value(value));
531 }
532 
Set(StringPiece key,const char16_t * value)533 Value* Value::Dict::Set(StringPiece key, const char16_t* value) & {
534   return Set(key, Value(value));
535 }
536 
Set(StringPiece key,std::string && value)537 Value* Value::Dict::Set(StringPiece key, std::string&& value) & {
538   return Set(key, Value(std::move(value)));
539 }
540 
Set(StringPiece key,BlobStorage && value)541 Value* Value::Dict::Set(StringPiece key, BlobStorage&& value) & {
542   return Set(key, Value(std::move(value)));
543 }
544 
Set(StringPiece key,Dict && value)545 Value* Value::Dict::Set(StringPiece key, Dict&& value) & {
546   return Set(key, Value(std::move(value)));
547 }
548 
Set(StringPiece key,List && value)549 Value* Value::Dict::Set(StringPiece key, List&& value) & {
550   return Set(key, Value(std::move(value)));
551 }
552 
Set(StringPiece key,Value && value)553 Value::Dict&& Value::Dict::Set(StringPiece key, Value&& value) && {
554   DCHECK(IsStringUTF8AllowingNoncharacters(key));
555   storage_.insert_or_assign(key, std::make_unique<Value>(std::move(value)));
556   return std::move(*this);
557 }
558 
Set(StringPiece key,bool value)559 Value::Dict&& Value::Dict::Set(StringPiece key, bool value) && {
560   return std::move(*this).Set(key, Value(value));
561 }
562 
Set(StringPiece key,int value)563 Value::Dict&& Value::Dict::Set(StringPiece key, int value) && {
564   return std::move(*this).Set(key, Value(value));
565 }
566 
Set(StringPiece key,double value)567 Value::Dict&& Value::Dict::Set(StringPiece key, double value) && {
568   return std::move(*this).Set(key, Value(value));
569 }
570 
Set(StringPiece key,StringPiece value)571 Value::Dict&& Value::Dict::Set(StringPiece key, StringPiece value) && {
572   return std::move(*this).Set(key, Value(value));
573 }
574 
Set(StringPiece key,StringPiece16 value)575 Value::Dict&& Value::Dict::Set(StringPiece key, StringPiece16 value) && {
576   return std::move(*this).Set(key, Value(value));
577 }
578 
Set(StringPiece key,const char * value)579 Value::Dict&& Value::Dict::Set(StringPiece key, const char* value) && {
580   return std::move(*this).Set(key, Value(value));
581 }
582 
Set(StringPiece key,const char16_t * value)583 Value::Dict&& Value::Dict::Set(StringPiece key, const char16_t* value) && {
584   return std::move(*this).Set(key, Value(value));
585 }
586 
Set(StringPiece key,std::string && value)587 Value::Dict&& Value::Dict::Set(StringPiece key, std::string&& value) && {
588   return std::move(*this).Set(key, Value(std::move(value)));
589 }
590 
Set(StringPiece key,BlobStorage && value)591 Value::Dict&& Value::Dict::Set(StringPiece key, BlobStorage&& value) && {
592   return std::move(*this).Set(key, Value(std::move(value)));
593 }
594 
Set(StringPiece key,Dict && value)595 Value::Dict&& Value::Dict::Set(StringPiece key, Dict&& value) && {
596   return std::move(*this).Set(key, Value(std::move(value)));
597 }
598 
Set(StringPiece key,List && value)599 Value::Dict&& Value::Dict::Set(StringPiece key, List&& value) && {
600   return std::move(*this).Set(key, Value(std::move(value)));
601 }
602 
Remove(StringPiece key)603 bool Value::Dict::Remove(StringPiece key) {
604   DCHECK(IsStringUTF8AllowingNoncharacters(key));
605 
606   return storage_.erase(key) > 0;
607 }
608 
Extract(StringPiece key)609 absl::optional<Value> Value::Dict::Extract(StringPiece key) {
610   DCHECK(IsStringUTF8AllowingNoncharacters(key));
611 
612   auto it = storage_.find(key);
613   if (it == storage_.end()) {
614     return absl::nullopt;
615   }
616   Value v = std::move(*it->second);
617   storage_.erase(it);
618   return v;
619 }
620 
FindByDottedPath(StringPiece path) const621 const Value* Value::Dict::FindByDottedPath(StringPiece path) const {
622   DCHECK(!path.empty());
623   DCHECK(IsStringUTF8AllowingNoncharacters(path));
624 
625   const Dict* current_dict = this;
626   const Value* current_value = nullptr;
627   PathSplitter splitter(path);
628   while (true) {
629     current_value = current_dict->Find(splitter.Next());
630     if (!splitter.HasNext()) {
631       return current_value;
632     }
633     if (!current_value) {
634       return nullptr;
635     }
636     current_dict = current_value->GetIfDict();
637     if (!current_dict) {
638       return nullptr;
639     }
640   }
641 }
642 
FindByDottedPath(StringPiece path)643 Value* Value::Dict::FindByDottedPath(StringPiece path) {
644   return const_cast<Value*>(std::as_const(*this).FindByDottedPath(path));
645 }
646 
FindBoolByDottedPath(StringPiece path) const647 absl::optional<bool> Value::Dict::FindBoolByDottedPath(StringPiece path) const {
648   const Value* v = FindByDottedPath(path);
649   return v ? v->GetIfBool() : absl::nullopt;
650 }
651 
FindIntByDottedPath(StringPiece path) const652 absl::optional<int> Value::Dict::FindIntByDottedPath(StringPiece path) const {
653   const Value* v = FindByDottedPath(path);
654   return v ? v->GetIfInt() : absl::nullopt;
655 }
656 
FindDoubleByDottedPath(StringPiece path) const657 absl::optional<double> Value::Dict::FindDoubleByDottedPath(
658     StringPiece path) const {
659   const Value* v = FindByDottedPath(path);
660   return v ? v->GetIfDouble() : absl::nullopt;
661 }
662 
FindStringByDottedPath(StringPiece path) const663 const std::string* Value::Dict::FindStringByDottedPath(StringPiece path) const {
664   const Value* v = FindByDottedPath(path);
665   return v ? v->GetIfString() : nullptr;
666 }
667 
FindStringByDottedPath(StringPiece path)668 std::string* Value::Dict::FindStringByDottedPath(StringPiece path) {
669   Value* v = FindByDottedPath(path);
670   return v ? v->GetIfString() : nullptr;
671 }
672 
FindBlobByDottedPath(StringPiece path) const673 const Value::BlobStorage* Value::Dict::FindBlobByDottedPath(
674     StringPiece path) const {
675   const Value* v = FindByDottedPath(path);
676   return v ? v->GetIfBlob() : nullptr;
677 }
678 
FindDictByDottedPath(StringPiece path) const679 const Value::Dict* Value::Dict::FindDictByDottedPath(StringPiece path) const {
680   const Value* v = FindByDottedPath(path);
681   return v ? v->GetIfDict() : nullptr;
682 }
683 
FindDictByDottedPath(StringPiece path)684 Value::Dict* Value::Dict::FindDictByDottedPath(StringPiece path) {
685   Value* v = FindByDottedPath(path);
686   return v ? v->GetIfDict() : nullptr;
687 }
688 
FindListByDottedPath(StringPiece path) const689 const Value::List* Value::Dict::FindListByDottedPath(StringPiece path) const {
690   const Value* v = FindByDottedPath(path);
691   return v ? v->GetIfList() : nullptr;
692 }
693 
FindListByDottedPath(StringPiece path)694 Value::List* Value::Dict::FindListByDottedPath(StringPiece path) {
695   Value* v = FindByDottedPath(path);
696   return v ? v->GetIfList() : nullptr;
697 }
698 
SetByDottedPath(StringPiece path,Value && value)699 Value* Value::Dict::SetByDottedPath(StringPiece path, Value&& value) {
700   DCHECK(!path.empty());
701   DCHECK(IsStringUTF8AllowingNoncharacters(path));
702 
703   Dict* current_dict = this;
704   Value* current_value = nullptr;
705   PathSplitter splitter(path);
706   while (true) {
707     StringPiece next_key = splitter.Next();
708     if (!splitter.HasNext()) {
709       return current_dict->Set(next_key, std::move(value));
710     }
711     // This could be clever to avoid a double-lookup via use of lower_bound(),
712     // but for now, just implement it the most straightforward way.
713     current_value = current_dict->Find(next_key);
714     if (current_value) {
715       // Unlike the legacy DictionaryValue API, encountering an intermediate
716       // node that is not a `Value::Type::DICT` is an error.
717       current_dict = current_value->GetIfDict();
718       if (!current_dict) {
719         return nullptr;
720       }
721     } else {
722       current_dict = &current_dict->Set(next_key, Dict())->GetDict();
723     }
724   }
725 }
726 
SetByDottedPath(StringPiece path,bool value)727 Value* Value::Dict::SetByDottedPath(StringPiece path, bool value) {
728   return SetByDottedPath(path, Value(value));
729 }
730 
SetByDottedPath(StringPiece path,int value)731 Value* Value::Dict::SetByDottedPath(StringPiece path, int value) {
732   return SetByDottedPath(path, Value(value));
733 }
734 
SetByDottedPath(StringPiece path,double value)735 Value* Value::Dict::SetByDottedPath(StringPiece path, double value) {
736   return SetByDottedPath(path, Value(value));
737 }
738 
SetByDottedPath(StringPiece path,StringPiece value)739 Value* Value::Dict::SetByDottedPath(StringPiece path, StringPiece value) {
740   return SetByDottedPath(path, Value(value));
741 }
742 
SetByDottedPath(StringPiece path,StringPiece16 value)743 Value* Value::Dict::SetByDottedPath(StringPiece path, StringPiece16 value) {
744   return SetByDottedPath(path, Value(value));
745 }
746 
SetByDottedPath(StringPiece path,const char * value)747 Value* Value::Dict::SetByDottedPath(StringPiece path, const char* value) {
748   return SetByDottedPath(path, Value(value));
749 }
750 
SetByDottedPath(StringPiece path,const char16_t * value)751 Value* Value::Dict::SetByDottedPath(StringPiece path, const char16_t* value) {
752   return SetByDottedPath(path, Value(value));
753 }
754 
SetByDottedPath(StringPiece path,std::string && value)755 Value* Value::Dict::SetByDottedPath(StringPiece path, std::string&& value) {
756   return SetByDottedPath(path, Value(std::move(value)));
757 }
758 
SetByDottedPath(StringPiece path,BlobStorage && value)759 Value* Value::Dict::SetByDottedPath(StringPiece path, BlobStorage&& value) {
760   return SetByDottedPath(path, Value(std::move(value)));
761 }
762 
SetByDottedPath(StringPiece path,Dict && value)763 Value* Value::Dict::SetByDottedPath(StringPiece path, Dict&& value) {
764   return SetByDottedPath(path, Value(std::move(value)));
765 }
766 
SetByDottedPath(StringPiece path,List && value)767 Value* Value::Dict::SetByDottedPath(StringPiece path, List&& value) {
768   return SetByDottedPath(path, Value(std::move(value)));
769 }
770 
RemoveByDottedPath(StringPiece path)771 bool Value::Dict::RemoveByDottedPath(StringPiece path) {
772   return ExtractByDottedPath(path).has_value();
773 }
774 
ExtractByDottedPath(StringPiece path)775 absl::optional<Value> Value::Dict::ExtractByDottedPath(StringPiece path) {
776   DCHECK(!path.empty());
777   DCHECK(IsStringUTF8AllowingNoncharacters(path));
778 
779   // Use recursion instead of PathSplitter here, as it simplifies code for
780   // removing dictionaries that become empty if a value matching `path` is
781   // extracted.
782   size_t dot_index = path.find('.');
783   if (dot_index == StringPiece::npos) {
784     return Extract(path);
785   }
786   // This could be clever to avoid a double-lookup by using storage_ directly,
787   // but for now, just implement it in the most straightforward way.
788   StringPiece next_key = path.substr(0, dot_index);
789   auto* next_dict = FindDict(next_key);
790   if (!next_dict) {
791     return absl::nullopt;
792   }
793   absl::optional<Value> extracted =
794       next_dict->ExtractByDottedPath(path.substr(dot_index + 1));
795   if (extracted && next_dict->empty()) {
796     Remove(next_key);
797   }
798   return extracted;
799 }
800 
EstimateMemoryUsage() const801 size_t Value::Dict::EstimateMemoryUsage() const {
802 #if BUILDFLAG(ENABLE_BASE_TRACING)
803   return base::trace_event::EstimateMemoryUsage(storage_);
804 #else   // BUILDFLAG(ENABLE_BASE_TRACING)
805   return 0;
806 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
807 }
808 
DebugString() const809 std::string Value::Dict::DebugString() const {
810   return DebugStringImpl(*this);
811 }
812 
813 #if BUILDFLAG(ENABLE_BASE_TRACING)
WriteIntoTrace(perfetto::TracedValue context) const814 void Value::Dict::WriteIntoTrace(perfetto::TracedValue context) const {
815   perfetto::TracedDictionary dict = std::move(context).WriteDictionary();
816   for (auto kv : *this) {
817     dict.Add(perfetto::DynamicString(kv.first), kv.second);
818   }
819 }
820 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
821 
Dict(const flat_map<std::string,std::unique_ptr<Value>> & storage)822 Value::Dict::Dict(
823     const flat_map<std::string, std::unique_ptr<Value>>& storage) {
824   storage_.reserve(storage.size());
825   for (const auto& [key, value] : storage) {
826     Set(key, value->Clone());
827   }
828 }
829 
operator ==(const Value::Dict & lhs,const Value::Dict & rhs)830 bool operator==(const Value::Dict& lhs, const Value::Dict& rhs) {
831   auto deref_2nd = [](const auto& p) { return std::tie(p.first, *p.second); };
832   return ranges::equal(lhs.storage_, rhs.storage_, {}, deref_2nd, deref_2nd);
833 }
834 
operator !=(const Value::Dict & lhs,const Value::Dict & rhs)835 bool operator!=(const Value::Dict& lhs, const Value::Dict& rhs) {
836   return !(lhs == rhs);
837 }
838 
operator <(const Value::Dict & lhs,const Value::Dict & rhs)839 bool operator<(const Value::Dict& lhs, const Value::Dict& rhs) {
840   auto deref_2nd = [](const auto& p) { return std::tie(p.first, *p.second); };
841   return ranges::lexicographical_compare(lhs.storage_, rhs.storage_, {},
842                                          deref_2nd, deref_2nd);
843 }
844 
operator >(const Value::Dict & lhs,const Value::Dict & rhs)845 bool operator>(const Value::Dict& lhs, const Value::Dict& rhs) {
846   return rhs < lhs;
847 }
848 
operator <=(const Value::Dict & lhs,const Value::Dict & rhs)849 bool operator<=(const Value::Dict& lhs, const Value::Dict& rhs) {
850   return !(rhs < lhs);
851 }
852 
operator >=(const Value::Dict & lhs,const Value::Dict & rhs)853 bool operator>=(const Value::Dict& lhs, const Value::Dict& rhs) {
854   return !(lhs < rhs);
855 }
856 
857 // static
with_capacity(size_t capacity)858 Value::List Value::List::with_capacity(size_t capacity) {
859   Value::List result;
860   result.reserve(capacity);
861   return result;
862 }
863 
864 Value::List::List() = default;
865 
866 Value::List::List(List&&) noexcept = default;
867 
868 Value::List& Value::List::operator=(List&&) noexcept = default;
869 
870 Value::List::~List() = default;
871 
empty() const872 bool Value::List::empty() const {
873   return storage_.empty();
874 }
875 
size() const876 size_t Value::List::size() const {
877   return storage_.size();
878 }
879 
begin()880 Value::List::iterator Value::List::begin() {
881   return iterator(base::to_address(storage_.begin()),
882                   base::to_address(storage_.end()));
883 }
884 
begin() const885 Value::List::const_iterator Value::List::begin() const {
886   return const_iterator(base::to_address(storage_.begin()),
887                         base::to_address(storage_.end()));
888 }
889 
cbegin() const890 Value::List::const_iterator Value::List::cbegin() const {
891   return const_iterator(base::to_address(storage_.cbegin()),
892                         base::to_address(storage_.cend()));
893 }
894 
end()895 Value::List::iterator Value::List::end() {
896   return iterator(base::to_address(storage_.begin()),
897                   base::to_address(storage_.end()),
898                   base::to_address(storage_.end()));
899 }
900 
end() const901 Value::List::const_iterator Value::List::end() const {
902   return const_iterator(base::to_address(storage_.begin()),
903                         base::to_address(storage_.end()),
904                         base::to_address(storage_.end()));
905 }
906 
cend() const907 Value::List::const_iterator Value::List::cend() const {
908   return const_iterator(base::to_address(storage_.cbegin()),
909                         base::to_address(storage_.cend()),
910                         base::to_address(storage_.cend()));
911 }
912 
front() const913 const Value& Value::List::front() const {
914   CHECK(!storage_.empty());
915   return storage_.front();
916 }
917 
front()918 Value& Value::List::front() {
919   CHECK(!storage_.empty());
920   return storage_.front();
921 }
922 
back() const923 const Value& Value::List::back() const {
924   CHECK(!storage_.empty());
925   return storage_.back();
926 }
927 
back()928 Value& Value::List::back() {
929   CHECK(!storage_.empty());
930   return storage_.back();
931 }
932 
reserve(size_t capacity)933 void Value::List::reserve(size_t capacity) {
934   storage_.reserve(capacity);
935 }
936 
operator [](size_t index) const937 const Value& Value::List::operator[](size_t index) const {
938   CHECK_LT(index, storage_.size());
939   return storage_[index];
940 }
941 
operator [](size_t index)942 Value& Value::List::operator[](size_t index) {
943   CHECK_LT(index, storage_.size());
944   return storage_[index];
945 }
946 
clear()947 void Value::List::clear() {
948   storage_.clear();
949 }
950 
erase(iterator pos)951 Value::List::iterator Value::List::erase(iterator pos) {
952   auto next_it = storage_.erase(storage_.begin() + (pos - begin()));
953   return iterator(base::to_address(storage_.begin()), base::to_address(next_it),
954                   base::to_address(storage_.end()));
955 }
956 
erase(const_iterator pos)957 Value::List::const_iterator Value::List::erase(const_iterator pos) {
958   auto next_it = storage_.erase(storage_.begin() + (pos - begin()));
959   return const_iterator(base::to_address(storage_.begin()),
960                         base::to_address(next_it),
961                         base::to_address(storage_.end()));
962 }
963 
erase(iterator first,iterator last)964 Value::List::iterator Value::List::erase(iterator first, iterator last) {
965   auto next_it = storage_.erase(storage_.begin() + (first - begin()),
966                                 storage_.begin() + (last - begin()));
967   return iterator(base::to_address(storage_.begin()), base::to_address(next_it),
968                   base::to_address(storage_.end()));
969 }
970 
erase(const_iterator first,const_iterator last)971 Value::List::const_iterator Value::List::erase(const_iterator first,
972                                                const_iterator last) {
973   auto next_it = storage_.erase(storage_.begin() + (first - begin()),
974                                 storage_.begin() + (last - begin()));
975   return const_iterator(base::to_address(storage_.begin()),
976                         base::to_address(next_it),
977                         base::to_address(storage_.end()));
978 }
979 
Clone() const980 Value::List Value::List::Clone() const {
981   return List(storage_);
982 }
983 
Append(Value && value)984 void Value::List::Append(Value&& value) & {
985   storage_.emplace_back(std::move(value));
986 }
987 
Append(bool value)988 void Value::List::Append(bool value) & {
989   storage_.emplace_back(value);
990 }
991 
Append(int value)992 void Value::List::Append(int value) & {
993   storage_.emplace_back(value);
994 }
995 
Append(double value)996 void Value::List::Append(double value) & {
997   storage_.emplace_back(value);
998 }
999 
Append(StringPiece value)1000 void Value::List::Append(StringPiece value) & {
1001   Append(Value(value));
1002 }
1003 
Append(StringPiece16 value)1004 void Value::List::Append(StringPiece16 value) & {
1005   storage_.emplace_back(value);
1006 }
1007 
Append(const char * value)1008 void Value::List::Append(const char* value) & {
1009   storage_.emplace_back(value);
1010 }
1011 
Append(const char16_t * value)1012 void Value::List::Append(const char16_t* value) & {
1013   storage_.emplace_back(value);
1014 }
1015 
Append(std::string && value)1016 void Value::List::Append(std::string&& value) & {
1017   storage_.emplace_back(std::move(value));
1018 }
1019 
Append(BlobStorage && value)1020 void Value::List::Append(BlobStorage&& value) & {
1021   storage_.emplace_back(std::move(value));
1022 }
1023 
Append(Dict && value)1024 void Value::List::Append(Dict&& value) & {
1025   storage_.emplace_back(std::move(value));
1026 }
1027 
Append(List && value)1028 void Value::List::Append(List&& value) & {
1029   storage_.emplace_back(std::move(value));
1030 }
1031 
Append(Value && value)1032 Value::List&& Value::List::Append(Value&& value) && {
1033   storage_.emplace_back(std::move(value));
1034   return std::move(*this);
1035 }
1036 
Append(bool value)1037 Value::List&& Value::List::Append(bool value) && {
1038   storage_.emplace_back(value);
1039   return std::move(*this);
1040 }
1041 
Append(int value)1042 Value::List&& Value::List::Append(int value) && {
1043   storage_.emplace_back(value);
1044   return std::move(*this);
1045 }
1046 
Append(double value)1047 Value::List&& Value::List::Append(double value) && {
1048   storage_.emplace_back(value);
1049   return std::move(*this);
1050 }
1051 
Append(StringPiece value)1052 Value::List&& Value::List::Append(StringPiece value) && {
1053   Append(Value(value));
1054   return std::move(*this);
1055 }
1056 
Append(StringPiece16 value)1057 Value::List&& Value::List::Append(StringPiece16 value) && {
1058   storage_.emplace_back(value);
1059   return std::move(*this);
1060 }
1061 
Append(const char * value)1062 Value::List&& Value::List::Append(const char* value) && {
1063   storage_.emplace_back(value);
1064   return std::move(*this);
1065 }
1066 
Append(const char16_t * value)1067 Value::List&& Value::List::Append(const char16_t* value) && {
1068   storage_.emplace_back(value);
1069   return std::move(*this);
1070 }
1071 
Append(std::string && value)1072 Value::List&& Value::List::Append(std::string&& value) && {
1073   storage_.emplace_back(std::move(value));
1074   return std::move(*this);
1075 }
1076 
Append(BlobStorage && value)1077 Value::List&& Value::List::Append(BlobStorage&& value) && {
1078   storage_.emplace_back(std::move(value));
1079   return std::move(*this);
1080 }
1081 
Append(Dict && value)1082 Value::List&& Value::List::Append(Dict&& value) && {
1083   storage_.emplace_back(std::move(value));
1084   return std::move(*this);
1085 }
1086 
Append(List && value)1087 Value::List&& Value::List::Append(List&& value) && {
1088   storage_.emplace_back(std::move(value));
1089   return std::move(*this);
1090 }
1091 
Insert(const_iterator pos,Value && value)1092 Value::List::iterator Value::List::Insert(const_iterator pos, Value&& value) {
1093   auto inserted_it =
1094       storage_.insert(storage_.begin() + (pos - begin()), std::move(value));
1095   return iterator(base::to_address(storage_.begin()),
1096                   base::to_address(inserted_it),
1097                   base::to_address(storage_.end()));
1098 }
1099 
EraseValue(const Value & value)1100 size_t Value::List::EraseValue(const Value& value) {
1101   return Erase(storage_, value);
1102 }
1103 
EstimateMemoryUsage() const1104 size_t Value::List::EstimateMemoryUsage() const {
1105 #if BUILDFLAG(ENABLE_BASE_TRACING)
1106   return base::trace_event::EstimateMemoryUsage(storage_);
1107 #else   // BUILDFLAG(ENABLE_BASE_TRACING)
1108   return 0;
1109 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
1110 }
1111 
DebugString() const1112 std::string Value::List::DebugString() const {
1113   return DebugStringImpl(*this);
1114 }
1115 
1116 #if BUILDFLAG(ENABLE_BASE_TRACING)
WriteIntoTrace(perfetto::TracedValue context) const1117 void Value::List::WriteIntoTrace(perfetto::TracedValue context) const {
1118   perfetto::TracedArray array = std::move(context).WriteArray();
1119   for (const auto& item : *this) {
1120     array.Append(item);
1121   }
1122 }
1123 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
1124 
List(const std::vector<Value> & storage)1125 Value::List::List(const std::vector<Value>& storage) {
1126   storage_.reserve(storage.size());
1127   for (const auto& value : storage) {
1128     storage_.push_back(value.Clone());
1129   }
1130 }
1131 
operator ==(const Value::List & lhs,const Value::List & rhs)1132 bool operator==(const Value::List& lhs, const Value::List& rhs) {
1133   return lhs.storage_ == rhs.storage_;
1134 }
1135 
operator !=(const Value::List & lhs,const Value::List & rhs)1136 bool operator!=(const Value::List& lhs, const Value::List& rhs) {
1137   return !(lhs == rhs);
1138 }
1139 
operator <(const Value::List & lhs,const Value::List & rhs)1140 bool operator<(const Value::List& lhs, const Value::List& rhs) {
1141   return lhs.storage_ < rhs.storage_;
1142 }
1143 
operator >(const Value::List & lhs,const Value::List & rhs)1144 bool operator>(const Value::List& lhs, const Value::List& rhs) {
1145   return rhs < lhs;
1146 }
1147 
operator <=(const Value::List & lhs,const Value::List & rhs)1148 bool operator<=(const Value::List& lhs, const Value::List& rhs) {
1149   return !(rhs < lhs);
1150 }
1151 
operator >=(const Value::List & lhs,const Value::List & rhs)1152 bool operator>=(const Value::List& lhs, const Value::List& rhs) {
1153   return !(lhs < rhs);
1154 }
1155 
FindBoolKey(StringPiece key) const1156 absl::optional<bool> Value::FindBoolKey(StringPiece key) const {
1157   return GetDict().FindBool(key);
1158 }
1159 
FindIntKey(StringPiece key) const1160 absl::optional<int> Value::FindIntKey(StringPiece key) const {
1161   return GetDict().FindInt(key);
1162 }
1163 
FindStringKey(StringPiece key) const1164 const std::string* Value::FindStringKey(StringPiece key) const {
1165   return GetDict().FindString(key);
1166 }
1167 
FindStringKey(StringPiece key)1168 std::string* Value::FindStringKey(StringPiece key) {
1169   return GetDict().FindString(key);
1170 }
1171 
FindListKey(StringPiece key) const1172 const Value* Value::FindListKey(StringPiece key) const {
1173   const Value* result = GetDict().Find(key);
1174   if (!result || result->type() != Type::LIST) {
1175     return nullptr;
1176   }
1177   return result;
1178 }
1179 
FindListKey(StringPiece key)1180 Value* Value::FindListKey(StringPiece key) {
1181   return const_cast<Value*>(std::as_const(*this).FindListKey(key));
1182 }
1183 
SetKey(StringPiece key,Value && value)1184 Value* Value::SetKey(StringPiece key, Value&& value) {
1185   return GetDict().Set(key, std::move(value));
1186 }
1187 
SetBoolKey(StringPiece key,bool value)1188 Value* Value::SetBoolKey(StringPiece key, bool value) {
1189   return GetDict().Set(key, value);
1190 }
1191 
SetIntKey(StringPiece key,int value)1192 Value* Value::SetIntKey(StringPiece key, int value) {
1193   return GetDict().Set(key, value);
1194 }
1195 
SetDoubleKey(StringPiece key,double value)1196 Value* Value::SetDoubleKey(StringPiece key, double value) {
1197   return GetDict().Set(key, value);
1198 }
1199 
SetStringKey(StringPiece key,StringPiece value)1200 Value* Value::SetStringKey(StringPiece key, StringPiece value) {
1201   return GetDict().Set(key, value);
1202 }
1203 
SetStringKey(StringPiece key,StringPiece16 value)1204 Value* Value::SetStringKey(StringPiece key, StringPiece16 value) {
1205   return GetDict().Set(key, value);
1206 }
1207 
SetStringKey(StringPiece key,const char * value)1208 Value* Value::SetStringKey(StringPiece key, const char* value) {
1209   return GetDict().Set(key, value);
1210 }
1211 
SetStringKey(StringPiece key,std::string && value)1212 Value* Value::SetStringKey(StringPiece key, std::string&& value) {
1213   return GetDict().Set(key, std::move(value));
1214 }
1215 
RemoveKey(StringPiece key)1216 bool Value::RemoveKey(StringPiece key) {
1217   return GetDict().Remove(key);
1218 }
1219 
FindPath(StringPiece path)1220 Value* Value::FindPath(StringPiece path) {
1221   return GetDict().FindByDottedPath(path);
1222 }
1223 
FindPath(StringPiece path) const1224 const Value* Value::FindPath(StringPiece path) const {
1225   return GetDict().FindByDottedPath(path);
1226 }
1227 
FindBoolPath(StringPiece path) const1228 absl::optional<bool> Value::FindBoolPath(StringPiece path) const {
1229   return GetDict().FindBoolByDottedPath(path);
1230 }
1231 
FindIntPath(StringPiece path) const1232 absl::optional<int> Value::FindIntPath(StringPiece path) const {
1233   return GetDict().FindIntByDottedPath(path);
1234 }
1235 
FindDoublePath(StringPiece path) const1236 absl::optional<double> Value::FindDoublePath(StringPiece path) const {
1237   return GetDict().FindDoubleByDottedPath(path);
1238 }
1239 
FindStringPath(StringPiece path) const1240 const std::string* Value::FindStringPath(StringPiece path) const {
1241   return GetDict().FindStringByDottedPath(path);
1242 }
1243 
FindStringPath(StringPiece path)1244 std::string* Value::FindStringPath(StringPiece path) {
1245   return GetDict().FindStringByDottedPath(path);
1246 }
1247 
FindDictPath(StringPiece path) const1248 const Value* Value::FindDictPath(StringPiece path) const {
1249   const Value* cur = GetDict().FindByDottedPath(path);
1250   if (!cur || cur->type() != Type::DICT) {
1251     return nullptr;
1252   }
1253   return cur;
1254 }
1255 
FindDictPath(StringPiece path)1256 Value* Value::FindDictPath(StringPiece path) {
1257   return const_cast<Value*>(std::as_const(*this).FindDictPath(path));
1258 }
1259 
FindListPath(StringPiece path) const1260 const Value* Value::FindListPath(StringPiece path) const {
1261   const Value* cur = GetDict().FindByDottedPath(path);
1262   if (!cur || cur->type() != Type::LIST) {
1263     return nullptr;
1264   }
1265   return cur;
1266 }
1267 
FindListPath(StringPiece path)1268 Value* Value::FindListPath(StringPiece path) {
1269   return const_cast<Value*>(std::as_const(*this).FindListPath(path));
1270 }
1271 
DictSize() const1272 size_t Value::DictSize() const {
1273   return GetDict().size();
1274 }
1275 
operator ==(const Value & lhs,const Value & rhs)1276 bool operator==(const Value& lhs, const Value& rhs) {
1277   return lhs.data_ == rhs.data_;
1278 }
1279 
operator !=(const Value & lhs,const Value & rhs)1280 bool operator!=(const Value& lhs, const Value& rhs) {
1281   return !(lhs == rhs);
1282 }
1283 
operator <(const Value & lhs,const Value & rhs)1284 bool operator<(const Value& lhs, const Value& rhs) {
1285   return lhs.data_ < rhs.data_;
1286 }
1287 
operator >(const Value & lhs,const Value & rhs)1288 bool operator>(const Value& lhs, const Value& rhs) {
1289   return rhs < lhs;
1290 }
1291 
operator <=(const Value & lhs,const Value & rhs)1292 bool operator<=(const Value& lhs, const Value& rhs) {
1293   return !(rhs < lhs);
1294 }
1295 
operator >=(const Value & lhs,const Value & rhs)1296 bool operator>=(const Value& lhs, const Value& rhs) {
1297   return !(lhs < rhs);
1298 }
1299 
operator ==(const Value & lhs,bool rhs)1300 bool operator==(const Value& lhs, bool rhs) {
1301   return lhs.is_bool() && lhs.GetBool() == rhs;
1302 }
1303 
operator ==(const Value & lhs,int rhs)1304 bool operator==(const Value& lhs, int rhs) {
1305   return lhs.is_int() && lhs.GetInt() == rhs;
1306 }
1307 
operator ==(const Value & lhs,double rhs)1308 bool operator==(const Value& lhs, double rhs) {
1309   return lhs.is_double() && lhs.GetDouble() == rhs;
1310 }
1311 
operator ==(const Value & lhs,StringPiece rhs)1312 bool operator==(const Value& lhs, StringPiece rhs) {
1313   return lhs.is_string() && lhs.GetString() == rhs;
1314 }
1315 
operator ==(const Value & lhs,const Value::Dict & rhs)1316 bool operator==(const Value& lhs, const Value::Dict& rhs) {
1317   return lhs.is_dict() && lhs.GetDict() == rhs;
1318 }
1319 
operator ==(const Value & lhs,const Value::List & rhs)1320 bool operator==(const Value& lhs, const Value::List& rhs) {
1321   return lhs.is_list() && lhs.GetList() == rhs;
1322 }
1323 
EstimateMemoryUsage() const1324 size_t Value::EstimateMemoryUsage() const {
1325   switch (type()) {
1326 #if BUILDFLAG(ENABLE_BASE_TRACING)
1327     case Type::STRING:
1328       return base::trace_event::EstimateMemoryUsage(GetString());
1329     case Type::BINARY:
1330       return base::trace_event::EstimateMemoryUsage(GetBlob());
1331     case Type::DICT:
1332       return GetDict().EstimateMemoryUsage();
1333     case Type::LIST:
1334       return GetList().EstimateMemoryUsage();
1335 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
1336     default:
1337       return 0;
1338   }
1339 }
1340 
DebugString() const1341 std::string Value::DebugString() const {
1342   return DebugStringImpl(*this);
1343 }
1344 
1345 #if BUILDFLAG(ENABLE_BASE_TRACING)
WriteIntoTrace(perfetto::TracedValue context) const1346 void Value::WriteIntoTrace(perfetto::TracedValue context) const {
1347   Visit([&](const auto& member) {
1348     using T = std::decay_t<decltype(member)>;
1349     if constexpr (std::is_same_v<T, absl::monostate>) {
1350       std::move(context).WriteString("<none>");
1351     } else if constexpr (std::is_same_v<T, bool>) {
1352       std::move(context).WriteBoolean(member);
1353     } else if constexpr (std::is_same_v<T, int>) {
1354       std::move(context).WriteInt64(member);
1355     } else if constexpr (std::is_same_v<T, DoubleStorage>) {
1356       std::move(context).WriteDouble(member);
1357     } else if constexpr (std::is_same_v<T, std::string>) {
1358       std::move(context).WriteString(member);
1359     } else if constexpr (std::is_same_v<T, BlobStorage>) {
1360       std::move(context).WriteString("<binary data not supported>");
1361     } else if constexpr (std::is_same_v<T, Dict>) {
1362       member.WriteIntoTrace(std::move(context));
1363     } else if constexpr (std::is_same_v<T, List>) {
1364       member.WriteIntoTrace(std::move(context));
1365     }
1366   });
1367 }
1368 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
1369 
ValueView(const Value & value)1370 ValueView::ValueView(const Value& value)
1371     : data_view_(
1372           value.Visit([](const auto& member) { return ViewType(member); })) {}
1373 
ToValue() const1374 Value ValueView::ToValue() const {
1375   return Value::CloningHelper::Clone(data_view_);
1376 }
1377 
1378 ValueSerializer::~ValueSerializer() = default;
1379 
1380 ValueDeserializer::~ValueDeserializer() = default;
1381 
operator <<(std::ostream & out,const Value & value)1382 std::ostream& operator<<(std::ostream& out, const Value& value) {
1383   return out << value.DebugString();
1384 }
1385 
operator <<(std::ostream & out,const Value::Dict & dict)1386 std::ostream& operator<<(std::ostream& out, const Value::Dict& dict) {
1387   return out << dict.DebugString();
1388 }
1389 
operator <<(std::ostream & out,const Value::List & list)1390 std::ostream& operator<<(std::ostream& out, const Value::List& list) {
1391   return out << list.DebugString();
1392 }
1393 
operator <<(std::ostream & out,const Value::Type & type)1394 std::ostream& operator<<(std::ostream& out, const Value::Type& type) {
1395   if (static_cast<int>(type) < 0 ||
1396       static_cast<size_t>(type) >= std::size(kTypeNames)) {
1397     return out << "Invalid Type (index = " << static_cast<int>(type) << ")";
1398   }
1399   return out << Value::GetTypeName(type);
1400 }
1401 
1402 }  // namespace base
1403