• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 <string.h>
8 
9 #include <algorithm>
10 #include <cmath>
11 #include <iterator>
12 #include <new>
13 #include <ostream>
14 #include <utility>
15 
16 #include "base/json/json_writer.h"
17 #include "base/logging.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 
23 namespace base {
24 
25 namespace {
26 
27 const char* const kTypeNames[] = {"null",   "boolean",    "integer", "string",
28                                   "binary", "dictionary", "list"};
29 static_assert(std::size(kTypeNames) ==
30                   static_cast<size_t>(Value::Type::LIST) + 1,
31               "kTypeNames Has Wrong Size");
32 
33 std::unique_ptr<Value> CopyWithoutEmptyChildren(const Value& node);
34 
35 // Make a deep copy of |node|, but don't include empty lists or dictionaries
36 // in the copy. It's possible for this function to return NULL and it
37 // expects |node| to always be non-NULL.
CopyListWithoutEmptyChildren(const Value & list)38 std::unique_ptr<Value> CopyListWithoutEmptyChildren(const Value& list) {
39   Value copy(Value::Type::LIST);
40   for (const auto& entry : list.GetList()) {
41     std::unique_ptr<Value> child_copy = CopyWithoutEmptyChildren(entry);
42     if (child_copy)
43       copy.GetList().push_back(std::move(*child_copy));
44   }
45   return copy.GetList().empty() ? nullptr
46                                 : std::make_unique<Value>(std::move(copy));
47 }
48 
CopyDictionaryWithoutEmptyChildren(const DictionaryValue & dict)49 std::unique_ptr<DictionaryValue> CopyDictionaryWithoutEmptyChildren(
50     const DictionaryValue& dict) {
51   std::unique_ptr<DictionaryValue> copy;
52   for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
53     std::unique_ptr<Value> child_copy = CopyWithoutEmptyChildren(it.value());
54     if (child_copy) {
55       if (!copy)
56         copy = std::make_unique<DictionaryValue>();
57       copy->SetWithoutPathExpansion(it.key(), std::move(child_copy));
58     }
59   }
60   return copy;
61 }
62 
CopyWithoutEmptyChildren(const Value & node)63 std::unique_ptr<Value> CopyWithoutEmptyChildren(const Value& node) {
64   switch (node.type()) {
65     case Value::Type::LIST:
66       return CopyListWithoutEmptyChildren(static_cast<const ListValue&>(node));
67 
68     case Value::Type::DICTIONARY:
69       return CopyDictionaryWithoutEmptyChildren(
70           static_cast<const DictionaryValue&>(node));
71 
72     default:
73       return std::make_unique<Value>(node.Clone());
74   }
75 }
76 
77 }  // namespace
78 
79 // static
CreateWithCopiedBuffer(const char * buffer,size_t size)80 std::unique_ptr<Value> Value::CreateWithCopiedBuffer(const char* buffer,
81                                                      size_t size) {
82   return std::make_unique<Value>(BlobStorage(buffer, buffer + size));
83 }
84 
85 // static
FromUniquePtrValue(std::unique_ptr<Value> val)86 Value Value::FromUniquePtrValue(std::unique_ptr<Value> val) {
87   return std::move(*val);
88 }
89 
90 // static
ToUniquePtrValue(Value val)91 std::unique_ptr<Value> Value::ToUniquePtrValue(Value val) {
92   return std::make_unique<Value>(std::move(val));
93 }
94 
Value(Value && that)95 Value::Value(Value&& that) noexcept {
96   InternalMoveConstructFrom(std::move(that));
97 }
98 
Value()99 Value::Value() noexcept : type_(Type::NONE) {}
100 
Value(Type type)101 Value::Value(Type type) : type_(type) {
102   // Initialize with the default value.
103   switch (type_) {
104     case Type::NONE:
105       return;
106 
107     case Type::BOOLEAN:
108       bool_value_ = false;
109       return;
110     case Type::INTEGER:
111       int_value_ = 0;
112       return;
113     case Type::STRING:
114       new (&string_value_) std::string();
115       return;
116     case Type::BINARY:
117       new (&binary_value_) BlobStorage();
118       return;
119     case Type::DICTIONARY:
120       new (&dict_) DictStorage();
121       return;
122     case Type::LIST:
123       new (&list_) ListStorage();
124       return;
125   }
126 }
127 
Value(bool in_bool)128 Value::Value(bool in_bool) : type_(Type::BOOLEAN), bool_value_(in_bool) {}
129 
Value(int in_int)130 Value::Value(int in_int) : type_(Type::INTEGER), int_value_(in_int) {}
131 
Value(const char * in_string)132 Value::Value(const char* in_string) : Value(std::string(in_string)) {}
133 
Value(std::string_view in_string)134 Value::Value(std::string_view in_string) : Value(std::string(in_string)) {}
135 
Value(std::string && in_string)136 Value::Value(std::string&& in_string) noexcept
137     : type_(Type::STRING), string_value_(std::move(in_string)) {
138   DCHECK(IsStringUTF8(string_value_));
139 }
140 
Value(const char16_t * in_string16)141 Value::Value(const char16_t* in_string16)
142     : Value(std::u16string_view(in_string16)) {}
143 
Value(std::u16string_view in_string16)144 Value::Value(std::u16string_view in_string16)
145     : Value(UTF16ToUTF8(in_string16)) {}
146 
Value(const BlobStorage & in_blob)147 Value::Value(const BlobStorage& in_blob)
148     : type_(Type::BINARY), binary_value_(in_blob) {}
149 
Value(BlobStorage && in_blob)150 Value::Value(BlobStorage&& in_blob) noexcept
151     : type_(Type::BINARY), binary_value_(std::move(in_blob)) {}
152 
Value(const DictStorage & in_dict)153 Value::Value(const DictStorage& in_dict) : type_(Type::DICTIONARY), dict_() {
154   dict_.reserve(in_dict.size());
155   for (const auto& it : in_dict) {
156     dict_.try_emplace(dict_.end(), it.first,
157                       std::make_unique<Value>(it.second->Clone()));
158   }
159 }
160 
Value(DictStorage && in_dict)161 Value::Value(DictStorage&& in_dict) noexcept
162     : type_(Type::DICTIONARY), dict_(std::move(in_dict)) {}
163 
Value(const ListStorage & in_list)164 Value::Value(const ListStorage& in_list) : type_(Type::LIST), list_() {
165   list_.reserve(in_list.size());
166   for (const auto& val : in_list)
167     list_.emplace_back(val.Clone());
168 }
169 
Value(ListStorage && in_list)170 Value::Value(ListStorage&& in_list) noexcept
171     : type_(Type::LIST), list_(std::move(in_list)) {}
172 
operator =(Value && that)173 Value& Value::operator=(Value&& that) noexcept {
174   InternalCleanup();
175   InternalMoveConstructFrom(std::move(that));
176 
177   return *this;
178 }
179 
Clone() const180 Value Value::Clone() const {
181   switch (type_) {
182     case Type::NONE:
183       return Value();
184     case Type::BOOLEAN:
185       return Value(bool_value_);
186     case Type::INTEGER:
187       return Value(int_value_);
188     case Type::STRING:
189       return Value(string_value_);
190     case Type::BINARY:
191       return Value(binary_value_);
192     case Type::DICTIONARY:
193       return Value(dict_);
194     case Type::LIST:
195       return Value(list_);
196   }
197 
198   NOTREACHED();
199   return Value();
200 }
201 
~Value()202 Value::~Value() {
203   InternalCleanup();
204 }
205 
206 // static
GetTypeName(Value::Type type)207 const char* Value::GetTypeName(Value::Type type) {
208   DCHECK_GE(static_cast<int>(type), 0);
209   DCHECK_LT(static_cast<size_t>(type), std::size(kTypeNames));
210   return kTypeNames[static_cast<size_t>(type)];
211 }
212 
GetBool() const213 bool Value::GetBool() const {
214   CHECK(is_bool());
215   return bool_value_;
216 }
217 
GetInt() const218 int Value::GetInt() const {
219   CHECK(is_int());
220   return int_value_;
221 }
222 
GetString() const223 const std::string& Value::GetString() const {
224   CHECK(is_string());
225   return string_value_;
226 }
227 
GetBlob() const228 const Value::BlobStorage& Value::GetBlob() const {
229   CHECK(is_blob());
230   return binary_value_;
231 }
232 
GetList()233 Value::ListStorage& Value::GetList() {
234   CHECK(is_list());
235   return list_;
236 }
237 
GetList() const238 const Value::ListStorage& Value::GetList() const {
239   CHECK(is_list());
240   return list_;
241 }
242 
FindKey(std::string_view key)243 Value* Value::FindKey(std::string_view key) {
244   return const_cast<Value*>(static_cast<const Value*>(this)->FindKey(key));
245 }
246 
FindKey(std::string_view key) const247 const Value* Value::FindKey(std::string_view key) const {
248   CHECK(is_dict());
249   auto found = dict_.find(key);
250   if (found == dict_.end())
251     return nullptr;
252   return found->second.get();
253 }
254 
FindKeyOfType(std::string_view key,Type type)255 Value* Value::FindKeyOfType(std::string_view key, Type type) {
256   return const_cast<Value*>(
257       static_cast<const Value*>(this)->FindKeyOfType(key, type));
258 }
259 
FindKeyOfType(std::string_view key,Type type) const260 const Value* Value::FindKeyOfType(std::string_view key, Type type) const {
261   const Value* result = FindKey(key);
262   if (!result || result->type() != type)
263     return nullptr;
264   return result;
265 }
266 
RemoveKey(std::string_view key)267 bool Value::RemoveKey(std::string_view key) {
268   CHECK(is_dict());
269   // NOTE: Can't directly return dict_->erase(key) due to MSVC warning C4800.
270   return dict_.erase(key) != 0;
271 }
272 
SetKey(std::string_view key,Value value)273 Value* Value::SetKey(std::string_view key, Value value) {
274   CHECK(is_dict());
275   // NOTE: We can't use |insert_or_assign| here, as only |try_emplace| does
276   // an explicit conversion from std::string_view to std::string if necessary.
277   auto val_ptr = std::make_unique<Value>(std::move(value));
278   auto result = dict_.try_emplace(key, std::move(val_ptr));
279   if (!result.second) {
280     // val_ptr is guaranteed to be still intact at this point.
281     result.first->second = std::move(val_ptr);
282   }
283   return result.first->second.get();
284 }
285 
SetKey(std::string && key,Value value)286 Value* Value::SetKey(std::string&& key, Value value) {
287   CHECK(is_dict());
288   return dict_
289       .insert_or_assign(std::move(key),
290                         std::make_unique<Value>(std::move(value)))
291       .first->second.get();
292 }
293 
SetKey(const char * key,Value value)294 Value* Value::SetKey(const char* key, Value value) {
295   return SetKey(std::string_view(key), std::move(value));
296 }
297 
FindPath(std::initializer_list<std::string_view> path)298 Value* Value::FindPath(std::initializer_list<std::string_view> path) {
299   return const_cast<Value*>(const_cast<const Value*>(this)->FindPath(path));
300 }
301 
FindPath(span<const std::string_view> path)302 Value* Value::FindPath(span<const std::string_view> path) {
303   return const_cast<Value*>(const_cast<const Value*>(this)->FindPath(path));
304 }
305 
FindPath(std::initializer_list<std::string_view> path) const306 const Value* Value::FindPath(
307     std::initializer_list<std::string_view> path) const {
308   DCHECK_GE(path.size(), 2u) << "Use FindKey() for a path of length 1.";
309   return FindPath(make_span(path.begin(), path.size()));
310 }
311 
FindPath(span<const std::string_view> path) const312 const Value* Value::FindPath(span<const std::string_view> path) const {
313   const Value* cur = this;
314   for (const std::string_view& component : path) {
315     if (!cur->is_dict() || (cur = cur->FindKey(component)) == nullptr)
316       return nullptr;
317   }
318   return cur;
319 }
320 
FindPathOfType(std::initializer_list<std::string_view> path,Type type)321 Value* Value::FindPathOfType(std::initializer_list<std::string_view> path,
322                              Type type) {
323   return const_cast<Value*>(
324       const_cast<const Value*>(this)->FindPathOfType(path, type));
325 }
326 
FindPathOfType(span<const std::string_view> path,Type type)327 Value* Value::FindPathOfType(span<const std::string_view> path, Type type) {
328   return const_cast<Value*>(
329       const_cast<const Value*>(this)->FindPathOfType(path, type));
330 }
331 
FindPathOfType(std::initializer_list<std::string_view> path,Type type) const332 const Value* Value::FindPathOfType(std::initializer_list<std::string_view> path,
333                                    Type type) const {
334   DCHECK_GE(path.size(), 2u) << "Use FindKeyOfType() for a path of length 1.";
335   return FindPathOfType(make_span(path.begin(), path.size()), type);
336 }
337 
FindPathOfType(span<const std::string_view> path,Type type) const338 const Value* Value::FindPathOfType(span<const std::string_view> path,
339                                    Type type) const {
340   const Value* result = FindPath(path);
341   if (!result || result->type() != type)
342     return nullptr;
343   return result;
344 }
345 
SetPath(std::initializer_list<std::string_view> path,Value value)346 Value* Value::SetPath(std::initializer_list<std::string_view> path,
347                       Value value) {
348   DCHECK_GE(path.size(), 2u) << "Use SetKey() for a path of length 1.";
349   return SetPath(make_span(path.begin(), path.size()), std::move(value));
350 }
351 
SetPath(span<const std::string_view> path,Value value)352 Value* Value::SetPath(span<const std::string_view> path, Value value) {
353   DCHECK_NE(path.begin(), path.end());  // Can't be empty path.
354 
355   // Walk/construct intermediate dictionaries. The last element requires
356   // special handling so skip it in this loop.
357   Value* cur = this;
358   const std::string_view* cur_path = path.begin();
359   for (; (cur_path + 1) < path.end(); ++cur_path) {
360     if (!cur->is_dict())
361       return nullptr;
362 
363     // Use lower_bound to avoid doing the search twice for missing keys.
364     const std::string_view path_component = *cur_path;
365     auto found = cur->dict_.lower_bound(path_component);
366     if (found == cur->dict_.end() || found->first != path_component) {
367       // No key found, insert one.
368       auto inserted = cur->dict_.try_emplace(
369           found, path_component, std::make_unique<Value>(Type::DICTIONARY));
370       cur = inserted->second.get();
371     } else {
372       cur = found->second.get();
373     }
374   }
375 
376   // "cur" will now contain the last dictionary to insert or replace into.
377   if (!cur->is_dict())
378     return nullptr;
379   return cur->SetKey(*cur_path, std::move(value));
380 }
381 
RemovePath(std::initializer_list<std::string_view> path)382 bool Value::RemovePath(std::initializer_list<std::string_view> path) {
383   DCHECK_GE(path.size(), 2u) << "Use RemoveKey() for a path of length 1.";
384   return RemovePath(make_span(path.begin(), path.size()));
385 }
386 
RemovePath(span<const std::string_view> path)387 bool Value::RemovePath(span<const std::string_view> path) {
388   if (!is_dict() || path.empty())
389     return false;
390 
391   if (path.size() == 1)
392     return RemoveKey(path[0]);
393 
394   auto found = dict_.find(path[0]);
395   if (found == dict_.end() || !found->second->is_dict())
396     return false;
397 
398   bool removed = found->second->RemovePath(path.subspan(1));
399   if (removed && found->second->dict_.empty())
400     dict_.erase(found);
401 
402   return removed;
403 }
404 
DictItems()405 Value::dict_iterator_proxy Value::DictItems() {
406   CHECK(is_dict());
407   return dict_iterator_proxy(&dict_);
408 }
409 
DictItems() const410 Value::const_dict_iterator_proxy Value::DictItems() const {
411   CHECK(is_dict());
412   return const_dict_iterator_proxy(&dict_);
413 }
414 
DictSize() const415 size_t Value::DictSize() const {
416   CHECK(is_dict());
417   return dict_.size();
418 }
419 
DictEmpty() const420 bool Value::DictEmpty() const {
421   CHECK(is_dict());
422   return dict_.empty();
423 }
424 
GetAsBoolean(bool * out_value) const425 bool Value::GetAsBoolean(bool* out_value) const {
426   if (out_value && is_bool()) {
427     *out_value = bool_value_;
428     return true;
429   }
430   return is_bool();
431 }
432 
GetAsInteger(int * out_value) const433 bool Value::GetAsInteger(int* out_value) const {
434   if (out_value && is_int()) {
435     *out_value = int_value_;
436     return true;
437   }
438   return is_int();
439 }
440 
GetAsString(std::string * out_value) const441 bool Value::GetAsString(std::string* out_value) const {
442   if (out_value && is_string()) {
443     *out_value = string_value_;
444     return true;
445   }
446   return is_string();
447 }
448 
GetAsString(std::u16string * out_value) const449 bool Value::GetAsString(std::u16string* out_value) const {
450   if (out_value && is_string()) {
451     *out_value = UTF8ToUTF16(string_value_);
452     return true;
453   }
454   return is_string();
455 }
456 
GetAsString(const Value ** out_value) const457 bool Value::GetAsString(const Value** out_value) const {
458   if (out_value && is_string()) {
459     *out_value = static_cast<const Value*>(this);
460     return true;
461   }
462   return is_string();
463 }
464 
GetAsString(std::string_view * out_value) const465 bool Value::GetAsString(std::string_view* out_value) const {
466   if (out_value && is_string()) {
467     *out_value = string_value_;
468     return true;
469   }
470   return is_string();
471 }
472 
GetAsList(ListValue ** out_value)473 bool Value::GetAsList(ListValue** out_value) {
474   if (out_value && is_list()) {
475     *out_value = static_cast<ListValue*>(this);
476     return true;
477   }
478   return is_list();
479 }
480 
GetAsList(const ListValue ** out_value) const481 bool Value::GetAsList(const ListValue** out_value) const {
482   if (out_value && is_list()) {
483     *out_value = static_cast<const ListValue*>(this);
484     return true;
485   }
486   return is_list();
487 }
488 
GetAsDictionary(DictionaryValue ** out_value)489 bool Value::GetAsDictionary(DictionaryValue** out_value) {
490   if (out_value && is_dict()) {
491     *out_value = static_cast<DictionaryValue*>(this);
492     return true;
493   }
494   return is_dict();
495 }
496 
GetAsDictionary(const DictionaryValue ** out_value) const497 bool Value::GetAsDictionary(const DictionaryValue** out_value) const {
498   if (out_value && is_dict()) {
499     *out_value = static_cast<const DictionaryValue*>(this);
500     return true;
501   }
502   return is_dict();
503 }
504 
DeepCopy() const505 Value* Value::DeepCopy() const {
506   return new Value(Clone());
507 }
508 
CreateDeepCopy() const509 std::unique_ptr<Value> Value::CreateDeepCopy() const {
510   return std::make_unique<Value>(Clone());
511 }
512 
operator ==(const Value & lhs,const Value & rhs)513 bool operator==(const Value& lhs, const Value& rhs) {
514   if (lhs.type_ != rhs.type_)
515     return false;
516 
517   switch (lhs.type_) {
518     case Value::Type::NONE:
519       return true;
520     case Value::Type::BOOLEAN:
521       return lhs.bool_value_ == rhs.bool_value_;
522     case Value::Type::INTEGER:
523       return lhs.int_value_ == rhs.int_value_;
524     case Value::Type::STRING:
525       return lhs.string_value_ == rhs.string_value_;
526     case Value::Type::BINARY:
527       return lhs.binary_value_ == rhs.binary_value_;
528     // TODO(crbug.com/646113): Clean this up when DictionaryValue and ListValue
529     // are completely inlined.
530     case Value::Type::DICTIONARY:
531       if (lhs.dict_.size() != rhs.dict_.size())
532         return false;
533       return std::equal(
534           std::begin(lhs.dict_), std::end(lhs.dict_), std::begin(rhs.dict_),
535           [](const auto& u, const auto& v) {
536             return std::tie(u.first, *u.second) == std::tie(v.first, *v.second);
537           });
538     case Value::Type::LIST:
539       return lhs.list_ == rhs.list_;
540   }
541 
542   NOTREACHED();
543   return false;
544 }
545 
operator !=(const Value & lhs,const Value & rhs)546 bool operator!=(const Value& lhs, const Value& rhs) {
547   return !(lhs == rhs);
548 }
549 
operator <(const Value & lhs,const Value & rhs)550 bool operator<(const Value& lhs, const Value& rhs) {
551   if (lhs.type_ != rhs.type_)
552     return lhs.type_ < rhs.type_;
553 
554   switch (lhs.type_) {
555     case Value::Type::NONE:
556       return false;
557     case Value::Type::BOOLEAN:
558       return lhs.bool_value_ < rhs.bool_value_;
559     case Value::Type::INTEGER:
560       return lhs.int_value_ < rhs.int_value_;
561     case Value::Type::STRING:
562       return lhs.string_value_ < rhs.string_value_;
563     case Value::Type::BINARY:
564       return lhs.binary_value_ < rhs.binary_value_;
565     // TODO(crbug.com/646113): Clean this up when DictionaryValue and ListValue
566     // are completely inlined.
567     case Value::Type::DICTIONARY:
568       return std::lexicographical_compare(
569           std::begin(lhs.dict_), std::end(lhs.dict_), std::begin(rhs.dict_),
570           std::end(rhs.dict_),
571           [](const Value::DictStorage::value_type& u,
572              const Value::DictStorage::value_type& v) {
573             return std::tie(u.first, *u.second) < std::tie(v.first, *v.second);
574           });
575     case Value::Type::LIST:
576       return lhs.list_ < rhs.list_;
577   }
578 
579   NOTREACHED();
580   return false;
581 }
582 
operator >(const Value & lhs,const Value & rhs)583 bool operator>(const Value& lhs, const Value& rhs) {
584   return rhs < lhs;
585 }
586 
operator <=(const Value & lhs,const Value & rhs)587 bool operator<=(const Value& lhs, const Value& rhs) {
588   return !(rhs < lhs);
589 }
590 
operator >=(const Value & lhs,const Value & rhs)591 bool operator>=(const Value& lhs, const Value& rhs) {
592   return !(lhs < rhs);
593 }
594 
Equals(const Value * other) const595 bool Value::Equals(const Value* other) const {
596   DCHECK(other);
597   return *this == *other;
598 }
599 
InternalMoveConstructFrom(Value && that)600 void Value::InternalMoveConstructFrom(Value&& that) {
601   type_ = that.type_;
602 
603   switch (type_) {
604     case Type::NONE:
605       return;
606     case Type::BOOLEAN:
607       bool_value_ = that.bool_value_;
608       return;
609     case Type::INTEGER:
610       int_value_ = that.int_value_;
611       return;
612     case Type::STRING:
613       new (&string_value_) std::string(std::move(that.string_value_));
614       return;
615     case Type::BINARY:
616       new (&binary_value_) BlobStorage(std::move(that.binary_value_));
617       return;
618     case Type::DICTIONARY:
619       new (&dict_) DictStorage(std::move(that.dict_));
620       return;
621     case Type::LIST:
622       new (&list_) ListStorage(std::move(that.list_));
623       return;
624   }
625 }
626 
InternalCleanup()627 void Value::InternalCleanup() {
628   switch (type_) {
629     case Type::NONE:
630     case Type::BOOLEAN:
631     case Type::INTEGER:
632       // Nothing to do
633       return;
634 
635     case Type::STRING:
636       string_value_.~basic_string();
637       return;
638     case Type::BINARY:
639       binary_value_.~BlobStorage();
640       return;
641     case Type::DICTIONARY:
642       dict_.~DictStorage();
643       return;
644     case Type::LIST:
645       list_.~ListStorage();
646       return;
647   }
648 }
649 
650 ///////////////////// DictionaryValue ////////////////////
651 
652 // static
From(std::unique_ptr<Value> value)653 std::unique_ptr<DictionaryValue> DictionaryValue::From(
654     std::unique_ptr<Value> value) {
655   DictionaryValue* out;
656   if (value && value->GetAsDictionary(&out)) {
657     [[maybe_unused]] auto released = value.release();
658     return WrapUnique(out);
659   }
660   return nullptr;
661 }
662 
DictionaryValue()663 DictionaryValue::DictionaryValue() : Value(Type::DICTIONARY) {}
DictionaryValue(const DictStorage & in_dict)664 DictionaryValue::DictionaryValue(const DictStorage& in_dict) : Value(in_dict) {}
DictionaryValue(DictStorage && in_dict)665 DictionaryValue::DictionaryValue(DictStorage&& in_dict) noexcept
666     : Value(std::move(in_dict)) {}
667 
HasKey(std::string_view key) const668 bool DictionaryValue::HasKey(std::string_view key) const {
669   DCHECK(IsStringUTF8(key));
670   auto current_entry = dict_.find(key);
671   DCHECK((current_entry == dict_.end()) || current_entry->second);
672   return current_entry != dict_.end();
673 }
674 
Clear()675 void DictionaryValue::Clear() {
676   dict_.clear();
677 }
678 
Set(std::string_view path,std::unique_ptr<Value> in_value)679 Value* DictionaryValue::Set(std::string_view path,
680                             std::unique_ptr<Value> in_value) {
681   DCHECK(IsStringUTF8(path));
682   DCHECK(in_value);
683 
684   std::string_view current_path(path);
685   Value* current_dictionary = this;
686   for (size_t delimiter_position = current_path.find('.');
687        delimiter_position != std::string_view::npos;
688        delimiter_position = current_path.find('.')) {
689     // Assume that we're indexing into a dictionary.
690     std::string_view key = current_path.substr(0, delimiter_position);
691     Value* child_dictionary =
692         current_dictionary->FindKeyOfType(key, Type::DICTIONARY);
693     if (!child_dictionary) {
694       child_dictionary =
695           current_dictionary->SetKey(key, Value(Type::DICTIONARY));
696     }
697 
698     current_dictionary = child_dictionary;
699     current_path = current_path.substr(delimiter_position + 1);
700   }
701 
702   return static_cast<DictionaryValue*>(current_dictionary)
703       ->SetWithoutPathExpansion(current_path, std::move(in_value));
704 }
705 
SetBoolean(std::string_view path,bool in_value)706 Value* DictionaryValue::SetBoolean(std::string_view path, bool in_value) {
707   return Set(path, std::make_unique<Value>(in_value));
708 }
709 
SetInteger(std::string_view path,int in_value)710 Value* DictionaryValue::SetInteger(std::string_view path, int in_value) {
711   return Set(path, std::make_unique<Value>(in_value));
712 }
713 
SetString(std::string_view path,std::string_view in_value)714 Value* DictionaryValue::SetString(std::string_view path,
715                                   std::string_view in_value) {
716   return Set(path, std::make_unique<Value>(in_value));
717 }
718 
SetString(std::string_view path,const std::u16string & in_value)719 Value* DictionaryValue::SetString(std::string_view path,
720                                   const std::u16string& in_value) {
721   return Set(path, std::make_unique<Value>(in_value));
722 }
723 
SetDictionary(std::string_view path,std::unique_ptr<DictionaryValue> in_value)724 DictionaryValue* DictionaryValue::SetDictionary(
725     std::string_view path,
726     std::unique_ptr<DictionaryValue> in_value) {
727   return static_cast<DictionaryValue*>(Set(path, std::move(in_value)));
728 }
729 
SetList(std::string_view path,std::unique_ptr<ListValue> in_value)730 ListValue* DictionaryValue::SetList(std::string_view path,
731                                     std::unique_ptr<ListValue> in_value) {
732   return static_cast<ListValue*>(Set(path, std::move(in_value)));
733 }
734 
SetWithoutPathExpansion(std::string_view key,std::unique_ptr<Value> in_value)735 Value* DictionaryValue::SetWithoutPathExpansion(
736     std::string_view key,
737     std::unique_ptr<Value> in_value) {
738   // NOTE: We can't use |insert_or_assign| here, as only |try_emplace| does
739   // an explicit conversion from std::string_view to std::string if necessary.
740   auto result = dict_.try_emplace(key, std::move(in_value));
741   if (!result.second) {
742     // in_value is guaranteed to be still intact at this point.
743     result.first->second = std::move(in_value);
744   }
745   return result.first->second.get();
746 }
747 
Get(std::string_view path,const Value ** out_value) const748 bool DictionaryValue::Get(std::string_view path,
749                           const Value** out_value) const {
750   DCHECK(IsStringUTF8(path));
751   std::string_view current_path(path);
752   const DictionaryValue* current_dictionary = this;
753   for (size_t delimiter_position = current_path.find('.');
754        delimiter_position != std::string::npos;
755        delimiter_position = current_path.find('.')) {
756     const DictionaryValue* child_dictionary = nullptr;
757     if (!current_dictionary->GetDictionaryWithoutPathExpansion(
758             current_path.substr(0, delimiter_position), &child_dictionary)) {
759       return false;
760     }
761 
762     current_dictionary = child_dictionary;
763     current_path = current_path.substr(delimiter_position + 1);
764   }
765 
766   return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
767 }
768 
Get(std::string_view path,Value ** out_value)769 bool DictionaryValue::Get(std::string_view path, Value** out_value) {
770   return static_cast<const DictionaryValue&>(*this).Get(
771       path, const_cast<const Value**>(out_value));
772 }
773 
GetBoolean(std::string_view path,bool * bool_value) const774 bool DictionaryValue::GetBoolean(std::string_view path,
775                                  bool* bool_value) const {
776   const Value* value;
777   if (!Get(path, &value))
778     return false;
779 
780   return value->GetAsBoolean(bool_value);
781 }
782 
GetInteger(std::string_view path,int * out_value) const783 bool DictionaryValue::GetInteger(std::string_view path, int* out_value) const {
784   const Value* value;
785   if (!Get(path, &value))
786     return false;
787 
788   return value->GetAsInteger(out_value);
789 }
790 
GetString(std::string_view path,std::string * out_value) const791 bool DictionaryValue::GetString(std::string_view path,
792                                 std::string* out_value) const {
793   const Value* value;
794   if (!Get(path, &value))
795     return false;
796 
797   return value->GetAsString(out_value);
798 }
799 
GetString(std::string_view path,std::u16string * out_value) const800 bool DictionaryValue::GetString(std::string_view path,
801                                 std::u16string* out_value) const {
802   const Value* value;
803   if (!Get(path, &value))
804     return false;
805 
806   return value->GetAsString(out_value);
807 }
808 
GetStringASCII(std::string_view path,std::string * out_value) const809 bool DictionaryValue::GetStringASCII(std::string_view path,
810                                      std::string* out_value) const {
811   std::string out;
812   if (!GetString(path, &out))
813     return false;
814 
815   if (!IsStringASCII(out)) {
816     NOTREACHED();
817     return false;
818   }
819 
820   out_value->assign(out);
821   return true;
822 }
823 
GetBinary(std::string_view path,const Value ** out_value) const824 bool DictionaryValue::GetBinary(std::string_view path,
825                                 const Value** out_value) const {
826   const Value* value;
827   bool result = Get(path, &value);
828   if (!result || !value->is_blob())
829     return false;
830 
831   if (out_value)
832     *out_value = value;
833 
834   return true;
835 }
836 
GetBinary(std::string_view path,Value ** out_value)837 bool DictionaryValue::GetBinary(std::string_view path, Value** out_value) {
838   return static_cast<const DictionaryValue&>(*this).GetBinary(
839       path, const_cast<const Value**>(out_value));
840 }
841 
GetDictionary(std::string_view path,const DictionaryValue ** out_value) const842 bool DictionaryValue::GetDictionary(std::string_view path,
843                                     const DictionaryValue** out_value) const {
844   const Value* value;
845   bool result = Get(path, &value);
846   if (!result || !value->is_dict())
847     return false;
848 
849   if (out_value)
850     *out_value = static_cast<const DictionaryValue*>(value);
851 
852   return true;
853 }
854 
GetDictionary(std::string_view path,DictionaryValue ** out_value)855 bool DictionaryValue::GetDictionary(std::string_view path,
856                                     DictionaryValue** out_value) {
857   return static_cast<const DictionaryValue&>(*this).GetDictionary(
858       path, const_cast<const DictionaryValue**>(out_value));
859 }
860 
GetList(std::string_view path,const ListValue ** out_value) const861 bool DictionaryValue::GetList(std::string_view path,
862                               const ListValue** out_value) const {
863   const Value* value;
864   bool result = Get(path, &value);
865   if (!result || !value->is_list())
866     return false;
867 
868   if (out_value)
869     *out_value = static_cast<const ListValue*>(value);
870 
871   return true;
872 }
873 
GetList(std::string_view path,ListValue ** out_value)874 bool DictionaryValue::GetList(std::string_view path, ListValue** out_value) {
875   return static_cast<const DictionaryValue&>(*this).GetList(
876       path, const_cast<const ListValue**>(out_value));
877 }
878 
GetWithoutPathExpansion(std::string_view key,const Value ** out_value) const879 bool DictionaryValue::GetWithoutPathExpansion(std::string_view key,
880                                               const Value** out_value) const {
881   DCHECK(IsStringUTF8(key));
882   auto entry_iterator = dict_.find(key);
883   if (entry_iterator == dict_.end())
884     return false;
885 
886   if (out_value)
887     *out_value = entry_iterator->second.get();
888   return true;
889 }
890 
GetWithoutPathExpansion(std::string_view key,Value ** out_value)891 bool DictionaryValue::GetWithoutPathExpansion(std::string_view key,
892                                               Value** out_value) {
893   return static_cast<const DictionaryValue&>(*this).GetWithoutPathExpansion(
894       key, const_cast<const Value**>(out_value));
895 }
896 
GetBooleanWithoutPathExpansion(std::string_view key,bool * out_value) const897 bool DictionaryValue::GetBooleanWithoutPathExpansion(std::string_view key,
898                                                      bool* out_value) const {
899   const Value* value;
900   if (!GetWithoutPathExpansion(key, &value))
901     return false;
902 
903   return value->GetAsBoolean(out_value);
904 }
905 
GetIntegerWithoutPathExpansion(std::string_view key,int * out_value) const906 bool DictionaryValue::GetIntegerWithoutPathExpansion(std::string_view key,
907                                                      int* out_value) const {
908   const Value* value;
909   if (!GetWithoutPathExpansion(key, &value))
910     return false;
911 
912   return value->GetAsInteger(out_value);
913 }
914 
GetStringWithoutPathExpansion(std::string_view key,std::string * out_value) const915 bool DictionaryValue::GetStringWithoutPathExpansion(
916     std::string_view key,
917     std::string* out_value) const {
918   const Value* value;
919   if (!GetWithoutPathExpansion(key, &value))
920     return false;
921 
922   return value->GetAsString(out_value);
923 }
924 
GetStringWithoutPathExpansion(std::string_view key,std::u16string * out_value) const925 bool DictionaryValue::GetStringWithoutPathExpansion(
926     std::string_view key,
927     std::u16string* out_value) const {
928   const Value* value;
929   if (!GetWithoutPathExpansion(key, &value))
930     return false;
931 
932   return value->GetAsString(out_value);
933 }
934 
GetDictionaryWithoutPathExpansion(std::string_view key,const DictionaryValue ** out_value) const935 bool DictionaryValue::GetDictionaryWithoutPathExpansion(
936     std::string_view key,
937     const DictionaryValue** out_value) const {
938   const Value* value;
939   bool result = GetWithoutPathExpansion(key, &value);
940   if (!result || !value->is_dict())
941     return false;
942 
943   if (out_value)
944     *out_value = static_cast<const DictionaryValue*>(value);
945 
946   return true;
947 }
948 
GetDictionaryWithoutPathExpansion(std::string_view key,DictionaryValue ** out_value)949 bool DictionaryValue::GetDictionaryWithoutPathExpansion(
950     std::string_view key,
951     DictionaryValue** out_value) {
952   const DictionaryValue& const_this =
953       static_cast<const DictionaryValue&>(*this);
954   return const_this.GetDictionaryWithoutPathExpansion(
955       key, const_cast<const DictionaryValue**>(out_value));
956 }
957 
GetListWithoutPathExpansion(std::string_view key,const ListValue ** out_value) const958 bool DictionaryValue::GetListWithoutPathExpansion(
959     std::string_view key,
960     const ListValue** out_value) const {
961   const Value* value;
962   bool result = GetWithoutPathExpansion(key, &value);
963   if (!result || !value->is_list())
964     return false;
965 
966   if (out_value)
967     *out_value = static_cast<const ListValue*>(value);
968 
969   return true;
970 }
971 
GetListWithoutPathExpansion(std::string_view key,ListValue ** out_value)972 bool DictionaryValue::GetListWithoutPathExpansion(std::string_view key,
973                                                   ListValue** out_value) {
974   return static_cast<const DictionaryValue&>(*this).GetListWithoutPathExpansion(
975       key, const_cast<const ListValue**>(out_value));
976 }
977 
Remove(std::string_view path,std::unique_ptr<Value> * out_value)978 bool DictionaryValue::Remove(std::string_view path,
979                              std::unique_ptr<Value>* out_value) {
980   DCHECK(IsStringUTF8(path));
981   std::string_view current_path(path);
982   DictionaryValue* current_dictionary = this;
983   size_t delimiter_position = current_path.rfind('.');
984   if (delimiter_position != std::string_view::npos) {
985     if (!GetDictionary(current_path.substr(0, delimiter_position),
986                        &current_dictionary))
987       return false;
988     current_path = current_path.substr(delimiter_position + 1);
989   }
990 
991   return current_dictionary->RemoveWithoutPathExpansion(current_path,
992                                                         out_value);
993 }
994 
RemoveWithoutPathExpansion(std::string_view key,std::unique_ptr<Value> * out_value)995 bool DictionaryValue::RemoveWithoutPathExpansion(
996     std::string_view key,
997     std::unique_ptr<Value>* out_value) {
998   DCHECK(IsStringUTF8(key));
999   auto entry_iterator = dict_.find(key);
1000   if (entry_iterator == dict_.end())
1001     return false;
1002 
1003   if (out_value)
1004     *out_value = std::move(entry_iterator->second);
1005   dict_.erase(entry_iterator);
1006   return true;
1007 }
1008 
RemovePath(std::string_view path,std::unique_ptr<Value> * out_value)1009 bool DictionaryValue::RemovePath(std::string_view path,
1010                                  std::unique_ptr<Value>* out_value) {
1011   bool result = false;
1012   size_t delimiter_position = path.find('.');
1013 
1014   if (delimiter_position == std::string::npos)
1015     return RemoveWithoutPathExpansion(path, out_value);
1016 
1017   std::string_view subdict_path = path.substr(0, delimiter_position);
1018   DictionaryValue* subdict = nullptr;
1019   if (!GetDictionary(subdict_path, &subdict))
1020     return false;
1021   result = subdict->RemovePath(path.substr(delimiter_position + 1), out_value);
1022   if (result && subdict->empty())
1023     RemoveWithoutPathExpansion(subdict_path, nullptr);
1024 
1025   return result;
1026 }
1027 
DeepCopyWithoutEmptyChildren() const1028 std::unique_ptr<DictionaryValue> DictionaryValue::DeepCopyWithoutEmptyChildren()
1029     const {
1030   std::unique_ptr<DictionaryValue> copy =
1031       CopyDictionaryWithoutEmptyChildren(*this);
1032   if (!copy)
1033     copy = std::make_unique<DictionaryValue>();
1034   return copy;
1035 }
1036 
MergeDictionary(const DictionaryValue * dictionary)1037 void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
1038   CHECK(dictionary->is_dict());
1039   for (DictionaryValue::Iterator it(*dictionary); !it.IsAtEnd(); it.Advance()) {
1040     const Value* merge_value = &it.value();
1041     // Check whether we have to merge dictionaries.
1042     if (merge_value->is_dict()) {
1043       DictionaryValue* sub_dict;
1044       if (GetDictionaryWithoutPathExpansion(it.key(), &sub_dict)) {
1045         sub_dict->MergeDictionary(
1046             static_cast<const DictionaryValue*>(merge_value));
1047         continue;
1048       }
1049     }
1050     // All other cases: Make a copy and hook it up.
1051     SetKey(it.key(), merge_value->Clone());
1052   }
1053 }
1054 
Swap(DictionaryValue * other)1055 void DictionaryValue::Swap(DictionaryValue* other) {
1056   CHECK(other->is_dict());
1057   dict_.swap(other->dict_);
1058 }
1059 
Iterator(const DictionaryValue & target)1060 DictionaryValue::Iterator::Iterator(const DictionaryValue& target)
1061     : target_(target), it_(target.dict_.begin()) {}
1062 
1063 DictionaryValue::Iterator::Iterator(const Iterator& other) = default;
1064 
1065 DictionaryValue::Iterator::~Iterator() = default;
1066 
DeepCopy() const1067 DictionaryValue* DictionaryValue::DeepCopy() const {
1068   return new DictionaryValue(dict_);
1069 }
1070 
CreateDeepCopy() const1071 std::unique_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const {
1072   return std::make_unique<DictionaryValue>(dict_);
1073 }
1074 
1075 ///////////////////// ListValue ////////////////////
1076 
1077 // static
From(std::unique_ptr<Value> value)1078 std::unique_ptr<ListValue> ListValue::From(std::unique_ptr<Value> value) {
1079   ListValue* out;
1080   if (value && value->GetAsList(&out)) {
1081     [[maybe_unused]] auto result = value.release();
1082     return WrapUnique(out);
1083   }
1084   return nullptr;
1085 }
1086 
ListValue()1087 ListValue::ListValue() : Value(Type::LIST) {}
ListValue(const ListStorage & in_list)1088 ListValue::ListValue(const ListStorage& in_list) : Value(in_list) {}
ListValue(ListStorage && in_list)1089 ListValue::ListValue(ListStorage&& in_list) noexcept
1090     : Value(std::move(in_list)) {}
1091 
Clear()1092 void ListValue::Clear() {
1093   list_.clear();
1094 }
1095 
Reserve(size_t n)1096 void ListValue::Reserve(size_t n) {
1097   list_.reserve(n);
1098 }
1099 
Set(size_t index,std::unique_ptr<Value> in_value)1100 bool ListValue::Set(size_t index, std::unique_ptr<Value> in_value) {
1101   if (!in_value)
1102     return false;
1103 
1104   if (index >= list_.size())
1105     list_.resize(index + 1);
1106 
1107   list_[index] = std::move(*in_value);
1108   return true;
1109 }
1110 
Get(size_t index,const Value ** out_value) const1111 bool ListValue::Get(size_t index, const Value** out_value) const {
1112   if (index >= list_.size())
1113     return false;
1114 
1115   if (out_value)
1116     *out_value = &list_[index];
1117 
1118   return true;
1119 }
1120 
Get(size_t index,Value ** out_value)1121 bool ListValue::Get(size_t index, Value** out_value) {
1122   return static_cast<const ListValue&>(*this).Get(
1123       index, const_cast<const Value**>(out_value));
1124 }
1125 
GetBoolean(size_t index,bool * bool_value) const1126 bool ListValue::GetBoolean(size_t index, bool* bool_value) const {
1127   const Value* value;
1128   if (!Get(index, &value))
1129     return false;
1130 
1131   return value->GetAsBoolean(bool_value);
1132 }
1133 
GetInteger(size_t index,int * out_value) const1134 bool ListValue::GetInteger(size_t index, int* out_value) const {
1135   const Value* value;
1136   if (!Get(index, &value))
1137     return false;
1138 
1139   return value->GetAsInteger(out_value);
1140 }
1141 
GetString(size_t index,std::string * out_value) const1142 bool ListValue::GetString(size_t index, std::string* out_value) const {
1143   const Value* value;
1144   if (!Get(index, &value))
1145     return false;
1146 
1147   return value->GetAsString(out_value);
1148 }
1149 
GetString(size_t index,std::u16string * out_value) const1150 bool ListValue::GetString(size_t index, std::u16string* out_value) const {
1151   const Value* value;
1152   if (!Get(index, &value))
1153     return false;
1154 
1155   return value->GetAsString(out_value);
1156 }
1157 
GetDictionary(size_t index,const DictionaryValue ** out_value) const1158 bool ListValue::GetDictionary(size_t index,
1159                               const DictionaryValue** out_value) const {
1160   const Value* value;
1161   bool result = Get(index, &value);
1162   if (!result || !value->is_dict())
1163     return false;
1164 
1165   if (out_value)
1166     *out_value = static_cast<const DictionaryValue*>(value);
1167 
1168   return true;
1169 }
1170 
GetDictionary(size_t index,DictionaryValue ** out_value)1171 bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) {
1172   return static_cast<const ListValue&>(*this).GetDictionary(
1173       index, const_cast<const DictionaryValue**>(out_value));
1174 }
1175 
GetList(size_t index,const ListValue ** out_value) const1176 bool ListValue::GetList(size_t index, const ListValue** out_value) const {
1177   const Value* value;
1178   bool result = Get(index, &value);
1179   if (!result || !value->is_list())
1180     return false;
1181 
1182   if (out_value)
1183     *out_value = static_cast<const ListValue*>(value);
1184 
1185   return true;
1186 }
1187 
GetList(size_t index,ListValue ** out_value)1188 bool ListValue::GetList(size_t index, ListValue** out_value) {
1189   return static_cast<const ListValue&>(*this).GetList(
1190       index, const_cast<const ListValue**>(out_value));
1191 }
1192 
Remove(size_t index,std::unique_ptr<Value> * out_value)1193 bool ListValue::Remove(size_t index, std::unique_ptr<Value>* out_value) {
1194   if (index >= list_.size())
1195     return false;
1196 
1197   if (out_value)
1198     *out_value = std::make_unique<Value>(std::move(list_[index]));
1199 
1200   list_.erase(list_.begin() + index);
1201   return true;
1202 }
1203 
Remove(const Value & value,size_t * index)1204 bool ListValue::Remove(const Value& value, size_t* index) {
1205   auto it = std::find(list_.begin(), list_.end(), value);
1206 
1207   if (it == list_.end())
1208     return false;
1209 
1210   if (index)
1211     *index = std::distance(list_.begin(), it);
1212 
1213   list_.erase(it);
1214   return true;
1215 }
1216 
Erase(iterator iter,std::unique_ptr<Value> * out_value)1217 ListValue::iterator ListValue::Erase(iterator iter,
1218                                      std::unique_ptr<Value>* out_value) {
1219   if (out_value)
1220     *out_value = std::make_unique<Value>(std::move(*iter));
1221 
1222   return list_.erase(iter);
1223 }
1224 
Append(std::unique_ptr<Value> in_value)1225 void ListValue::Append(std::unique_ptr<Value> in_value) {
1226   list_.push_back(std::move(*in_value));
1227 }
1228 
AppendBoolean(bool in_value)1229 void ListValue::AppendBoolean(bool in_value) {
1230   list_.emplace_back(in_value);
1231 }
1232 
AppendInteger(int in_value)1233 void ListValue::AppendInteger(int in_value) {
1234   list_.emplace_back(in_value);
1235 }
1236 
AppendString(std::string_view in_value)1237 void ListValue::AppendString(std::string_view in_value) {
1238   list_.emplace_back(in_value);
1239 }
1240 
AppendString(const std::u16string & in_value)1241 void ListValue::AppendString(const std::u16string& in_value) {
1242   list_.emplace_back(in_value);
1243 }
1244 
AppendStrings(const std::vector<std::string> & in_values)1245 void ListValue::AppendStrings(const std::vector<std::string>& in_values) {
1246   list_.reserve(list_.size() + in_values.size());
1247   for (const auto& in_value : in_values)
1248     list_.emplace_back(in_value);
1249 }
1250 
AppendStrings(const std::vector<std::u16string> & in_values)1251 void ListValue::AppendStrings(const std::vector<std::u16string>& in_values) {
1252   list_.reserve(list_.size() + in_values.size());
1253   for (const auto& in_value : in_values)
1254     list_.emplace_back(in_value);
1255 }
1256 
AppendIfNotPresent(std::unique_ptr<Value> in_value)1257 bool ListValue::AppendIfNotPresent(std::unique_ptr<Value> in_value) {
1258   DCHECK(in_value);
1259   if (ContainsValue(list_, *in_value))
1260     return false;
1261 
1262   list_.push_back(std::move(*in_value));
1263   return true;
1264 }
1265 
Insert(size_t index,std::unique_ptr<Value> in_value)1266 bool ListValue::Insert(size_t index, std::unique_ptr<Value> in_value) {
1267   DCHECK(in_value);
1268   if (index > list_.size())
1269     return false;
1270 
1271   list_.insert(list_.begin() + index, std::move(*in_value));
1272   return true;
1273 }
1274 
Find(const Value & value) const1275 ListValue::const_iterator ListValue::Find(const Value& value) const {
1276   return std::find(list_.begin(), list_.end(), value);
1277 }
1278 
Swap(ListValue * other)1279 void ListValue::Swap(ListValue* other) {
1280   CHECK(other->is_list());
1281   list_.swap(other->list_);
1282 }
1283 
DeepCopy() const1284 ListValue* ListValue::DeepCopy() const {
1285   return new ListValue(list_);
1286 }
1287 
CreateDeepCopy() const1288 std::unique_ptr<ListValue> ListValue::CreateDeepCopy() const {
1289   return std::make_unique<ListValue>(list_);
1290 }
1291 
1292 ValueSerializer::~ValueSerializer() = default;
1293 
1294 ValueDeserializer::~ValueDeserializer() = default;
1295 
operator <<(std::ostream & out,const Value & value)1296 std::ostream& operator<<(std::ostream& out, const Value& value) {
1297   std::string json;
1298   JSONWriter::WriteWithOptions(value, JSONWriter::OPTIONS_PRETTY_PRINT, &json);
1299   return out << json;
1300 }
1301 
operator <<(std::ostream & out,const Value::Type & type)1302 std::ostream& operator<<(std::ostream& out, const Value::Type& type) {
1303   if (static_cast<int>(type) < 0 ||
1304       static_cast<size_t>(type) >= std::size(kTypeNames))
1305     return out << "Invalid Type (index = " << static_cast<int>(type) << ")";
1306   return out << Value::GetTypeName(type);
1307 }
1308 
1309 }  // namespace base
1310