Roll skia to r1241.
[chromium-blink-merge.git] / base / values.cc
blob0f30e379eb3301d915c0b06d1c78066fa993f10f
1 // Copyright (c) 2011 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.
5 #include "base/values.h"
7 #include "base/logging.h"
8 #include "base/string_util.h"
9 #include "base/utf_string_conversions.h"
11 namespace {
13 // Make a deep copy of |node|, but don't include empty lists or dictionaries
14 // in the copy. It's possible for this function to return NULL and it
15 // expects |node| to always be non-NULL.
16 Value* CopyWithoutEmptyChildren(Value* node) {
17 DCHECK(node);
18 switch (node->GetType()) {
19 case Value::TYPE_LIST: {
20 ListValue* list = static_cast<ListValue*>(node);
21 ListValue* copy = new ListValue;
22 for (ListValue::const_iterator it = list->begin(); it != list->end();
23 ++it) {
24 Value* child_copy = CopyWithoutEmptyChildren(*it);
25 if (child_copy)
26 copy->Append(child_copy);
28 if (!copy->empty())
29 return copy;
31 delete copy;
32 return NULL;
35 case Value::TYPE_DICTIONARY: {
36 DictionaryValue* dict = static_cast<DictionaryValue*>(node);
37 DictionaryValue* copy = new DictionaryValue;
38 for (DictionaryValue::key_iterator it = dict->begin_keys();
39 it != dict->end_keys(); ++it) {
40 Value* child = NULL;
41 bool rv = dict->GetWithoutPathExpansion(*it, &child);
42 DCHECK(rv);
43 Value* child_copy = CopyWithoutEmptyChildren(child);
44 if (child_copy)
45 copy->SetWithoutPathExpansion(*it, child_copy);
47 if (!copy->empty())
48 return copy;
50 delete copy;
51 return NULL;
54 default:
55 // For everything else, just make a copy.
56 return node->DeepCopy();
60 } // namespace
62 ///////////////////// Value ////////////////////
64 Value::~Value() {
67 // static
68 Value* Value::CreateNullValue() {
69 return new Value(TYPE_NULL);
72 // static
73 FundamentalValue* Value::CreateBooleanValue(bool in_value) {
74 return new FundamentalValue(in_value);
77 // static
78 FundamentalValue* Value::CreateIntegerValue(int in_value) {
79 return new FundamentalValue(in_value);
82 // static
83 FundamentalValue* Value::CreateDoubleValue(double in_value) {
84 return new FundamentalValue(in_value);
87 // static
88 StringValue* Value::CreateStringValue(const std::string& in_value) {
89 return new StringValue(in_value);
92 // static
93 StringValue* Value::CreateStringValue(const string16& in_value) {
94 return new StringValue(in_value);
97 // static
98 BinaryValue* Value::CreateBinaryValue(char* buffer, size_t size) {
99 return BinaryValue::Create(buffer, size);
102 bool Value::GetAsBoolean(bool* out_value) const {
103 return false;
106 bool Value::GetAsInteger(int* out_value) const {
107 return false;
110 bool Value::GetAsDouble(double* out_value) const {
111 return false;
114 bool Value::GetAsString(std::string* out_value) const {
115 return false;
118 bool Value::GetAsString(string16* out_value) const {
119 return false;
122 bool Value::GetAsList(ListValue** out_value) {
123 return false;
126 Value* Value::DeepCopy() const {
127 // This method should only be getting called for null Values--all subclasses
128 // need to provide their own implementation;.
129 DCHECK(IsType(TYPE_NULL));
130 return CreateNullValue();
133 bool Value::Equals(const Value* other) const {
134 // This method should only be getting called for null Values--all subclasses
135 // need to provide their own implementation;.
136 DCHECK(IsType(TYPE_NULL));
137 return other->IsType(TYPE_NULL);
140 // static
141 bool Value::Equals(const Value* a, const Value* b) {
142 if ((a == NULL) && (b == NULL)) return true;
143 if ((a == NULL) ^ (b == NULL)) return false;
144 return a->Equals(b);
147 Value::Value(ValueType type) : type_(type) {
150 ///////////////////// FundamentalValue ////////////////////
152 FundamentalValue::FundamentalValue(bool in_value)
153 : Value(TYPE_BOOLEAN), boolean_value_(in_value) {
156 FundamentalValue::FundamentalValue(int in_value)
157 : Value(TYPE_INTEGER), integer_value_(in_value) {
160 FundamentalValue::FundamentalValue(double in_value)
161 : Value(TYPE_DOUBLE), double_value_(in_value) {
164 FundamentalValue::~FundamentalValue() {
167 bool FundamentalValue::GetAsBoolean(bool* out_value) const {
168 if (out_value && IsType(TYPE_BOOLEAN))
169 *out_value = boolean_value_;
170 return (IsType(TYPE_BOOLEAN));
173 bool FundamentalValue::GetAsInteger(int* out_value) const {
174 if (out_value && IsType(TYPE_INTEGER))
175 *out_value = integer_value_;
176 return (IsType(TYPE_INTEGER));
179 bool FundamentalValue::GetAsDouble(double* out_value) const {
180 if (out_value && IsType(TYPE_DOUBLE))
181 *out_value = double_value_;
182 else if (out_value && IsType(TYPE_INTEGER))
183 *out_value = integer_value_;
184 return (IsType(TYPE_DOUBLE) || IsType(TYPE_INTEGER));
187 FundamentalValue* FundamentalValue::DeepCopy() const {
188 switch (GetType()) {
189 case TYPE_BOOLEAN:
190 return CreateBooleanValue(boolean_value_);
192 case TYPE_INTEGER:
193 return CreateIntegerValue(integer_value_);
195 case TYPE_DOUBLE:
196 return CreateDoubleValue(double_value_);
198 default:
199 NOTREACHED();
200 return NULL;
204 bool FundamentalValue::Equals(const Value* other) const {
205 if (other->GetType() != GetType())
206 return false;
208 switch (GetType()) {
209 case TYPE_BOOLEAN: {
210 bool lhs, rhs;
211 return GetAsBoolean(&lhs) && other->GetAsBoolean(&rhs) && lhs == rhs;
213 case TYPE_INTEGER: {
214 int lhs, rhs;
215 return GetAsInteger(&lhs) && other->GetAsInteger(&rhs) && lhs == rhs;
217 case TYPE_DOUBLE: {
218 double lhs, rhs;
219 return GetAsDouble(&lhs) && other->GetAsDouble(&rhs) && lhs == rhs;
221 default:
222 NOTREACHED();
223 return false;
227 ///////////////////// StringValue ////////////////////
229 StringValue::StringValue(const std::string& in_value)
230 : Value(TYPE_STRING),
231 value_(in_value) {
232 DCHECK(IsStringUTF8(in_value));
235 StringValue::StringValue(const string16& in_value)
236 : Value(TYPE_STRING),
237 value_(UTF16ToUTF8(in_value)) {
240 StringValue::~StringValue() {
243 bool StringValue::GetAsString(std::string* out_value) const {
244 if (out_value)
245 *out_value = value_;
246 return true;
249 bool StringValue::GetAsString(string16* out_value) const {
250 if (out_value)
251 *out_value = UTF8ToUTF16(value_);
252 return true;
255 StringValue* StringValue::DeepCopy() const {
256 return CreateStringValue(value_);
259 bool StringValue::Equals(const Value* other) const {
260 if (other->GetType() != GetType())
261 return false;
262 std::string lhs, rhs;
263 return GetAsString(&lhs) && other->GetAsString(&rhs) && lhs == rhs;
266 ///////////////////// BinaryValue ////////////////////
268 BinaryValue::~BinaryValue() {
269 DCHECK(buffer_);
270 if (buffer_)
271 delete[] buffer_;
274 // static
275 BinaryValue* BinaryValue::Create(char* buffer, size_t size) {
276 if (!buffer)
277 return NULL;
279 return new BinaryValue(buffer, size);
282 // static
283 BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer,
284 size_t size) {
285 if (!buffer)
286 return NULL;
288 char* buffer_copy = new char[size];
289 memcpy(buffer_copy, buffer, size);
290 return new BinaryValue(buffer_copy, size);
293 BinaryValue* BinaryValue::DeepCopy() const {
294 return CreateWithCopiedBuffer(buffer_, size_);
297 bool BinaryValue::Equals(const Value* other) const {
298 if (other->GetType() != GetType())
299 return false;
300 const BinaryValue* other_binary = static_cast<const BinaryValue*>(other);
301 if (other_binary->size_ != size_)
302 return false;
303 return !memcmp(buffer_, other_binary->buffer_, size_);
306 BinaryValue::BinaryValue(char* buffer, size_t size)
307 : Value(TYPE_BINARY),
308 buffer_(buffer),
309 size_(size) {
310 DCHECK(buffer_);
313 ///////////////////// DictionaryValue ////////////////////
315 DictionaryValue::DictionaryValue()
316 : Value(TYPE_DICTIONARY) {
319 DictionaryValue::~DictionaryValue() {
320 Clear();
323 bool DictionaryValue::HasKey(const std::string& key) const {
324 DCHECK(IsStringUTF8(key));
325 ValueMap::const_iterator current_entry = dictionary_.find(key);
326 DCHECK((current_entry == dictionary_.end()) || current_entry->second);
327 return current_entry != dictionary_.end();
330 void DictionaryValue::Clear() {
331 ValueMap::iterator dict_iterator = dictionary_.begin();
332 while (dict_iterator != dictionary_.end()) {
333 delete dict_iterator->second;
334 ++dict_iterator;
337 dictionary_.clear();
340 void DictionaryValue::Set(const std::string& path, Value* in_value) {
341 DCHECK(IsStringUTF8(path));
342 DCHECK(in_value);
344 std::string current_path(path);
345 DictionaryValue* current_dictionary = this;
346 for (size_t delimiter_position = current_path.find('.');
347 delimiter_position != std::string::npos;
348 delimiter_position = current_path.find('.')) {
349 // Assume that we're indexing into a dictionary.
350 std::string key(current_path, 0, delimiter_position);
351 DictionaryValue* child_dictionary = NULL;
352 if (!current_dictionary->GetDictionary(key, &child_dictionary)) {
353 child_dictionary = new DictionaryValue;
354 current_dictionary->SetWithoutPathExpansion(key, child_dictionary);
357 current_dictionary = child_dictionary;
358 current_path.erase(0, delimiter_position + 1);
361 current_dictionary->SetWithoutPathExpansion(current_path, in_value);
364 void DictionaryValue::SetBoolean(const std::string& path, bool in_value) {
365 Set(path, CreateBooleanValue(in_value));
368 void DictionaryValue::SetInteger(const std::string& path, int in_value) {
369 Set(path, CreateIntegerValue(in_value));
372 void DictionaryValue::SetDouble(const std::string& path, double in_value) {
373 Set(path, CreateDoubleValue(in_value));
376 void DictionaryValue::SetString(const std::string& path,
377 const std::string& in_value) {
378 Set(path, CreateStringValue(in_value));
381 void DictionaryValue::SetString(const std::string& path,
382 const string16& in_value) {
383 Set(path, CreateStringValue(in_value));
386 void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
387 Value* in_value) {
388 // If there's an existing value here, we need to delete it, because
389 // we own all our children.
390 if (HasKey(key)) {
391 DCHECK(dictionary_[key] != in_value); // This would be bogus
392 delete dictionary_[key];
395 dictionary_[key] = in_value;
398 bool DictionaryValue::Get(const std::string& path, Value** out_value) const {
399 DCHECK(IsStringUTF8(path));
400 std::string current_path(path);
401 const DictionaryValue* current_dictionary = this;
402 for (size_t delimiter_position = current_path.find('.');
403 delimiter_position != std::string::npos;
404 delimiter_position = current_path.find('.')) {
405 DictionaryValue* child_dictionary = NULL;
406 if (!current_dictionary->GetDictionary(
407 current_path.substr(0, delimiter_position), &child_dictionary))
408 return false;
410 current_dictionary = child_dictionary;
411 current_path.erase(0, delimiter_position + 1);
414 return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
417 bool DictionaryValue::GetBoolean(const std::string& path,
418 bool* bool_value) const {
419 Value* value;
420 if (!Get(path, &value))
421 return false;
423 return value->GetAsBoolean(bool_value);
426 bool DictionaryValue::GetInteger(const std::string& path,
427 int* out_value) const {
428 Value* value;
429 if (!Get(path, &value))
430 return false;
432 return value->GetAsInteger(out_value);
435 bool DictionaryValue::GetDouble(const std::string& path,
436 double* out_value) const {
437 Value* value;
438 if (!Get(path, &value))
439 return false;
441 return value->GetAsDouble(out_value);
444 bool DictionaryValue::GetString(const std::string& path,
445 std::string* out_value) const {
446 Value* value;
447 if (!Get(path, &value))
448 return false;
450 return value->GetAsString(out_value);
453 bool DictionaryValue::GetString(const std::string& path,
454 string16* out_value) const {
455 Value* value;
456 if (!Get(path, &value))
457 return false;
459 return value->GetAsString(out_value);
462 bool DictionaryValue::GetStringASCII(const std::string& path,
463 std::string* out_value) const {
464 std::string out;
465 if (!GetString(path, &out))
466 return false;
468 if (!IsStringASCII(out)) {
469 NOTREACHED();
470 return false;
473 out_value->assign(out);
474 return true;
477 bool DictionaryValue::GetBinary(const std::string& path,
478 BinaryValue** out_value) const {
479 Value* value;
480 bool result = Get(path, &value);
481 if (!result || !value->IsType(TYPE_BINARY))
482 return false;
484 if (out_value)
485 *out_value = static_cast<BinaryValue*>(value);
487 return true;
490 bool DictionaryValue::GetDictionary(const std::string& path,
491 DictionaryValue** out_value) const {
492 Value* value;
493 bool result = Get(path, &value);
494 if (!result || !value->IsType(TYPE_DICTIONARY))
495 return false;
497 if (out_value)
498 *out_value = static_cast<DictionaryValue*>(value);
500 return true;
503 bool DictionaryValue::GetList(const std::string& path,
504 ListValue** out_value) const {
505 Value* value;
506 bool result = Get(path, &value);
507 if (!result || !value->IsType(TYPE_LIST))
508 return false;
510 if (out_value)
511 *out_value = static_cast<ListValue*>(value);
513 return true;
516 bool DictionaryValue::GetWithoutPathExpansion(const std::string& key,
517 Value** out_value) const {
518 DCHECK(IsStringUTF8(key));
519 ValueMap::const_iterator entry_iterator = dictionary_.find(key);
520 if (entry_iterator == dictionary_.end())
521 return false;
523 Value* entry = entry_iterator->second;
524 if (out_value)
525 *out_value = entry;
526 return true;
529 bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::string& key,
530 int* out_value) const {
531 Value* value;
532 if (!GetWithoutPathExpansion(key, &value))
533 return false;
535 return value->GetAsInteger(out_value);
538 bool DictionaryValue::GetDoubleWithoutPathExpansion(const std::string& key,
539 double* out_value) const {
540 Value* value;
541 if (!GetWithoutPathExpansion(key, &value))
542 return false;
544 return value->GetAsDouble(out_value);
547 bool DictionaryValue::GetStringWithoutPathExpansion(
548 const std::string& key,
549 std::string* out_value) const {
550 Value* value;
551 if (!GetWithoutPathExpansion(key, &value))
552 return false;
554 return value->GetAsString(out_value);
557 bool DictionaryValue::GetStringWithoutPathExpansion(
558 const std::string& key,
559 string16* out_value) const {
560 Value* value;
561 if (!GetWithoutPathExpansion(key, &value))
562 return false;
564 return value->GetAsString(out_value);
567 bool DictionaryValue::GetDictionaryWithoutPathExpansion(
568 const std::string& key,
569 DictionaryValue** out_value) const {
570 Value* value;
571 bool result = GetWithoutPathExpansion(key, &value);
572 if (!result || !value->IsType(TYPE_DICTIONARY))
573 return false;
575 if (out_value)
576 *out_value = static_cast<DictionaryValue*>(value);
578 return true;
581 bool DictionaryValue::GetListWithoutPathExpansion(const std::string& key,
582 ListValue** out_value) const {
583 Value* value;
584 bool result = GetWithoutPathExpansion(key, &value);
585 if (!result || !value->IsType(TYPE_LIST))
586 return false;
588 if (out_value)
589 *out_value = static_cast<ListValue*>(value);
591 return true;
594 bool DictionaryValue::Remove(const std::string& path, Value** out_value) {
595 DCHECK(IsStringUTF8(path));
596 std::string current_path(path);
597 DictionaryValue* current_dictionary = this;
598 size_t delimiter_position = current_path.rfind('.');
599 if (delimiter_position != std::string::npos) {
600 if (!GetDictionary(current_path.substr(0, delimiter_position),
601 &current_dictionary))
602 return false;
603 current_path.erase(0, delimiter_position + 1);
606 return current_dictionary->RemoveWithoutPathExpansion(current_path,
607 out_value);
610 bool DictionaryValue::RemoveWithoutPathExpansion(const std::string& key,
611 Value** out_value) {
612 DCHECK(IsStringUTF8(key));
613 ValueMap::iterator entry_iterator = dictionary_.find(key);
614 if (entry_iterator == dictionary_.end())
615 return false;
617 Value* entry = entry_iterator->second;
618 if (out_value)
619 *out_value = entry;
620 else
621 delete entry;
622 dictionary_.erase(entry_iterator);
623 return true;
626 DictionaryValue* DictionaryValue::DeepCopyWithoutEmptyChildren() {
627 Value* copy = CopyWithoutEmptyChildren(this);
628 return copy ? static_cast<DictionaryValue*>(copy) : new DictionaryValue;
631 void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
632 for (DictionaryValue::key_iterator key(dictionary->begin_keys());
633 key != dictionary->end_keys(); ++key) {
634 Value* merge_value;
635 if (dictionary->GetWithoutPathExpansion(*key, &merge_value)) {
636 // Check whether we have to merge dictionaries.
637 if (merge_value->IsType(Value::TYPE_DICTIONARY)) {
638 DictionaryValue* sub_dict;
639 if (GetDictionaryWithoutPathExpansion(*key, &sub_dict)) {
640 sub_dict->MergeDictionary(
641 static_cast<const DictionaryValue*>(merge_value));
642 continue;
645 // All other cases: Make a copy and hook it up.
646 SetWithoutPathExpansion(*key, merge_value->DeepCopy());
651 DictionaryValue* DictionaryValue::DeepCopy() const {
652 DictionaryValue* result = new DictionaryValue;
654 for (ValueMap::const_iterator current_entry(dictionary_.begin());
655 current_entry != dictionary_.end(); ++current_entry) {
656 result->SetWithoutPathExpansion(current_entry->first,
657 current_entry->second->DeepCopy());
660 return result;
663 bool DictionaryValue::Equals(const Value* other) const {
664 if (other->GetType() != GetType())
665 return false;
667 const DictionaryValue* other_dict =
668 static_cast<const DictionaryValue*>(other);
669 key_iterator lhs_it(begin_keys());
670 key_iterator rhs_it(other_dict->begin_keys());
671 while (lhs_it != end_keys() && rhs_it != other_dict->end_keys()) {
672 Value* lhs;
673 Value* rhs;
674 if (*lhs_it != *rhs_it ||
675 !GetWithoutPathExpansion(*lhs_it, &lhs) ||
676 !other_dict->GetWithoutPathExpansion(*rhs_it, &rhs) ||
677 !lhs->Equals(rhs)) {
678 return false;
680 ++lhs_it;
681 ++rhs_it;
683 if (lhs_it != end_keys() || rhs_it != other_dict->end_keys())
684 return false;
686 return true;
689 ///////////////////// ListValue ////////////////////
691 ListValue::ListValue() : Value(TYPE_LIST) {
694 ListValue::~ListValue() {
695 Clear();
698 void ListValue::Clear() {
699 for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i)
700 delete *i;
701 list_.clear();
704 bool ListValue::Set(size_t index, Value* in_value) {
705 if (!in_value)
706 return false;
708 if (index >= list_.size()) {
709 // Pad out any intermediate indexes with null settings
710 while (index > list_.size())
711 Append(CreateNullValue());
712 Append(in_value);
713 } else {
714 DCHECK(list_[index] != in_value);
715 delete list_[index];
716 list_[index] = in_value;
718 return true;
721 bool ListValue::Get(size_t index, Value** out_value) const {
722 if (index >= list_.size())
723 return false;
725 if (out_value)
726 *out_value = list_[index];
728 return true;
731 bool ListValue::GetBoolean(size_t index, bool* bool_value) const {
732 Value* value;
733 if (!Get(index, &value))
734 return false;
736 return value->GetAsBoolean(bool_value);
739 bool ListValue::GetInteger(size_t index, int* out_value) const {
740 Value* value;
741 if (!Get(index, &value))
742 return false;
744 return value->GetAsInteger(out_value);
747 bool ListValue::GetDouble(size_t index, double* out_value) const {
748 Value* value;
749 if (!Get(index, &value))
750 return false;
752 return value->GetAsDouble(out_value);
755 bool ListValue::GetString(size_t index, std::string* out_value) const {
756 Value* value;
757 if (!Get(index, &value))
758 return false;
760 return value->GetAsString(out_value);
763 bool ListValue::GetString(size_t index, string16* out_value) const {
764 Value* value;
765 if (!Get(index, &value))
766 return false;
768 return value->GetAsString(out_value);
771 bool ListValue::GetBinary(size_t index, BinaryValue** out_value) const {
772 Value* value;
773 bool result = Get(index, &value);
774 if (!result || !value->IsType(TYPE_BINARY))
775 return false;
777 if (out_value)
778 *out_value = static_cast<BinaryValue*>(value);
780 return true;
783 bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) const {
784 Value* value;
785 bool result = Get(index, &value);
786 if (!result || !value->IsType(TYPE_DICTIONARY))
787 return false;
789 if (out_value)
790 *out_value = static_cast<DictionaryValue*>(value);
792 return true;
795 bool ListValue::GetList(size_t index, ListValue** out_value) const {
796 Value* value;
797 bool result = Get(index, &value);
798 if (!result || !value->IsType(TYPE_LIST))
799 return false;
801 if (out_value)
802 *out_value = static_cast<ListValue*>(value);
804 return true;
807 bool ListValue::Remove(size_t index, Value** out_value) {
808 if (index >= list_.size())
809 return false;
811 if (out_value)
812 *out_value = list_[index];
813 else
814 delete list_[index];
816 list_.erase(list_.begin() + index);
817 return true;
820 int ListValue::Remove(const Value& value) {
821 for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) {
822 if ((*i)->Equals(&value)) {
823 size_t index = i - list_.begin();
824 delete *i;
825 list_.erase(i);
827 // TODO(anyone): Returning a signed int type here is just wrong.
828 // Change this interface to return a size_t.
829 DCHECK(index <= INT_MAX);
830 int return_index = static_cast<int>(index);
831 return return_index;
834 return -1;
837 void ListValue::Append(Value* in_value) {
838 DCHECK(in_value);
839 list_.push_back(in_value);
842 bool ListValue::AppendIfNotPresent(Value* in_value) {
843 DCHECK(in_value);
844 for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) {
845 if ((*i)->Equals(in_value)) {
846 delete in_value;
847 return false;
850 list_.push_back(in_value);
851 return true;
854 bool ListValue::Insert(size_t index, Value* in_value) {
855 DCHECK(in_value);
856 if (index > list_.size())
857 return false;
859 list_.insert(list_.begin() + index, in_value);
860 return true;
863 bool ListValue::GetAsList(ListValue** out_value) {
864 if (out_value)
865 *out_value = this;
866 return true;
869 ListValue* ListValue::DeepCopy() const {
870 ListValue* result = new ListValue;
872 for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i)
873 result->Append((*i)->DeepCopy());
875 return result;
878 bool ListValue::Equals(const Value* other) const {
879 if (other->GetType() != GetType())
880 return false;
882 const ListValue* other_list =
883 static_cast<const ListValue*>(other);
884 const_iterator lhs_it, rhs_it;
885 for (lhs_it = begin(), rhs_it = other_list->begin();
886 lhs_it != end() && rhs_it != other_list->end();
887 ++lhs_it, ++rhs_it) {
888 if (!(*lhs_it)->Equals(*rhs_it))
889 return false;
891 if (lhs_it != end() || rhs_it != other_list->end())
892 return false;
894 return true;
897 ValueSerializer::~ValueSerializer() {