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