• 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 <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 = &current_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