blob: 716fdf3230d3ba8397a3cf08cd9c78864bbcd7f5 [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// Copyright (c) 2006-2008 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.
initial.commit3f4a7322008-07-27 06:49:38 +09004
5#include "base/logging.h"
scherkus@chromium.org2b923e72008-12-11 10:23:17 +09006#include "base/string_util.h"
initial.commit3f4a7322008-07-27 06:49:38 +09007#include "base/values.h"
8
9///////////////////// Value ////////////////////
10
11Value::~Value() {
12}
13
14// static
15Value* Value::CreateNullValue() {
16 return new Value(TYPE_NULL);
17}
18
19// static
20Value* Value::CreateBooleanValue(bool in_value) {
21 return new FundamentalValue(in_value);
22}
23
24// static
25Value* Value::CreateIntegerValue(int in_value) {
26 return new FundamentalValue(in_value);
27}
28
29// static
30Value* Value::CreateRealValue(double in_value) {
31 return new FundamentalValue(in_value);
32}
33
34// static
scherkus@chromium.org2b923e72008-12-11 10:23:17 +090035Value* Value::CreateStringValue(const std::string& in_value) {
36 return new StringValue(in_value);
37}
38
39// static
scherkus@chromium.org92bc0d42008-12-11 07:18:47 +090040Value* Value::CreateStringValue(const std::wstring& in_value) {
scherkus@chromium.org5ad62762008-12-11 07:30:57 +090041 return new StringValue(in_value);
scherkus@chromium.org92bc0d42008-12-11 07:18:47 +090042}
43
44// static
initial.commit3f4a7322008-07-27 06:49:38 +090045BinaryValue* Value::CreateBinaryValue(char* buffer, size_t size) {
46 return BinaryValue::Create(buffer, size);
47}
48
49bool Value::GetAsBoolean(bool* in_value) const {
50 return false;
51}
52
53bool Value::GetAsInteger(int* in_value) const {
54 return false;
55}
56
57bool Value::GetAsReal(double* in_value) const {
58 return false;
59}
60
scherkus@chromium.org2b923e72008-12-11 10:23:17 +090061bool Value::GetAsString(std::string* in_value) const {
62 return false;
63}
64
initial.commit3f4a7322008-07-27 06:49:38 +090065bool Value::GetAsString(std::wstring* in_value) const {
66 return false;
67}
68
69Value* Value::DeepCopy() const {
70 // This method should only be getting called for null Values--all subclasses
71 // need to provide their own implementation;.
72 DCHECK(IsType(TYPE_NULL));
73 return CreateNullValue();
74}
75
76bool Value::Equals(const Value* other) const {
77 // This method should only be getting called for null Values--all subclasses
78 // need to provide their own implementation;.
79 DCHECK(IsType(TYPE_NULL));
80 return other->IsType(TYPE_NULL);
81}
82
83///////////////////// FundamentalValue ////////////////////
84
85FundamentalValue::~FundamentalValue() {
86}
87
88bool FundamentalValue::GetAsBoolean(bool* out_value) const {
89 if (out_value && IsType(TYPE_BOOLEAN))
90 *out_value = boolean_value_;
91 return (IsType(TYPE_BOOLEAN));
92}
93
94bool FundamentalValue::GetAsInteger(int* out_value) const {
95 if (out_value && IsType(TYPE_INTEGER))
96 *out_value = integer_value_;
97 return (IsType(TYPE_INTEGER));
98}
99
100bool FundamentalValue::GetAsReal(double* out_value) const {
101 if (out_value && IsType(TYPE_REAL))
102 *out_value = real_value_;
103 return (IsType(TYPE_REAL));
104}
105
106Value* FundamentalValue::DeepCopy() const {
107 switch (GetType()) {
108 case TYPE_BOOLEAN:
109 return CreateBooleanValue(boolean_value_);
110
111 case TYPE_INTEGER:
112 return CreateIntegerValue(integer_value_);
113
114 case TYPE_REAL:
115 return CreateRealValue(real_value_);
116
117 default:
118 NOTREACHED();
119 return NULL;
120 }
121}
122
123bool FundamentalValue::Equals(const Value* other) const {
124 if (other->GetType() != GetType())
125 return false;
126
127 switch (GetType()) {
128 case TYPE_BOOLEAN: {
129 bool lhs, rhs;
130 return GetAsBoolean(&lhs) && other->GetAsBoolean(&rhs) && lhs == rhs;
131 }
132 case TYPE_INTEGER: {
133 int lhs, rhs;
134 return GetAsInteger(&lhs) && other->GetAsInteger(&rhs) && lhs == rhs;
135 }
136 case TYPE_REAL: {
137 double lhs, rhs;
138 return GetAsReal(&lhs) && other->GetAsReal(&rhs) && lhs == rhs;
139 }
140 default:
141 NOTREACHED();
142 return false;
143 }
144}
145
146///////////////////// StringValue ////////////////////
147
scherkus@chromium.org2b923e72008-12-11 10:23:17 +0900148StringValue::StringValue(const std::string& in_value)
149 : Value(TYPE_STRING),
150 value_(in_value) {
151 DCHECK(IsStringUTF8(in_value));
152}
153
154StringValue::StringValue(const std::wstring& in_value)
155 : Value(TYPE_STRING),
156 value_(WideToUTF8(in_value)) {
157}
158
initial.commit3f4a7322008-07-27 06:49:38 +0900159StringValue::~StringValue() {
160}
161
scherkus@chromium.org2b923e72008-12-11 10:23:17 +0900162bool StringValue::GetAsString(std::string* out_value) const {
163 if (out_value)
164 *out_value = value_;
165 return true;
166}
167
initial.commit3f4a7322008-07-27 06:49:38 +0900168bool StringValue::GetAsString(std::wstring* out_value) const {
169 if (out_value)
scherkus@chromium.org2b923e72008-12-11 10:23:17 +0900170 *out_value = UTF8ToWide(value_);
initial.commit3f4a7322008-07-27 06:49:38 +0900171 return true;
172}
173
174Value* StringValue::DeepCopy() const {
175 return CreateStringValue(value_);
176}
177
178bool StringValue::Equals(const Value* other) const {
179 if (other->GetType() != GetType())
180 return false;
scherkus@chromium.org2b923e72008-12-11 10:23:17 +0900181 std::string lhs, rhs;
initial.commit3f4a7322008-07-27 06:49:38 +0900182 return GetAsString(&lhs) && other->GetAsString(&rhs) && lhs == rhs;
183}
184
185///////////////////// BinaryValue ////////////////////
186
187//static
188BinaryValue* BinaryValue::Create(char* buffer, size_t size) {
189 if (!buffer)
190 return NULL;
191
192 return new BinaryValue(buffer, size);
193}
194
195//static
196BinaryValue* BinaryValue::CreateWithCopiedBuffer(char* buffer, size_t size) {
197 if (!buffer)
198 return NULL;
199
200 char* buffer_copy = new char[size];
mmentovai@google.com4a5b6272008-08-07 00:46:59 +0900201 memcpy(buffer_copy, buffer, size);
initial.commit3f4a7322008-07-27 06:49:38 +0900202 return new BinaryValue(buffer_copy, size);
203}
204
205
206BinaryValue::BinaryValue(char* buffer, size_t size)
207 : Value(TYPE_BINARY),
208 buffer_(buffer),
209 size_(size) {
210 DCHECK(buffer_);
211}
212
213BinaryValue::~BinaryValue() {
214 DCHECK(buffer_);
215 if (buffer_)
216 delete[] buffer_;
217}
218
219Value* BinaryValue::DeepCopy() const {
220 return CreateWithCopiedBuffer(buffer_, size_);
221}
222
223bool BinaryValue::Equals(const Value* other) const {
224 if (other->GetType() != GetType())
225 return false;
226 const BinaryValue* other_binary = static_cast<const BinaryValue*>(other);
227 if (other_binary->size_ != size_)
228 return false;
229 return !memcmp(buffer_, other_binary->buffer_, size_);
230}
231
232///////////////////// DictionaryValue ////////////////////
233
234DictionaryValue::~DictionaryValue() {
235 Clear();
236}
237
238void DictionaryValue::Clear() {
239 ValueMap::iterator dict_iterator = dictionary_.begin();
240 while (dict_iterator != dictionary_.end()) {
241 delete dict_iterator->second;
242 ++dict_iterator;
243 }
244
245 dictionary_.clear();
246}
247
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900248bool DictionaryValue::HasKey(const std::wstring& key) const {
initial.commit3f4a7322008-07-27 06:49:38 +0900249 ValueMap::const_iterator current_entry = dictionary_.find(key);
250 DCHECK((current_entry == dictionary_.end()) || current_entry->second);
251 return current_entry != dictionary_.end();
252}
253
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900254void DictionaryValue::SetInCurrentNode(const std::wstring& key,
initial.commit3f4a7322008-07-27 06:49:38 +0900255 Value* in_value) {
256 // If there's an existing value here, we need to delete it, because
257 // we own all our children.
258 if (HasKey(key)) {
259 DCHECK(dictionary_[key] != in_value); // This would be bogus
260 delete dictionary_[key];
261 }
262
263 dictionary_[key] = in_value;
264}
265
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900266bool DictionaryValue::Set(const std::wstring& path, Value* in_value) {
initial.commit3f4a7322008-07-27 06:49:38 +0900267 DCHECK(in_value);
268
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900269 std::wstring key = path;
initial.commit3f4a7322008-07-27 06:49:38 +0900270
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900271 size_t delimiter_position = path.find_first_of(L".", 0);
initial.commit3f4a7322008-07-27 06:49:38 +0900272 // If there isn't a dictionary delimiter in the path, we're done.
273 if (delimiter_position == std::wstring::npos) {
274 SetInCurrentNode(key, in_value);
275 return true;
276 } else {
277 key = path.substr(0, delimiter_position);
278 }
279
280 // Assume that we're indexing into a dictionary.
281 DictionaryValue* entry = NULL;
initial.commit3f4a7322008-07-27 06:49:38 +0900282 if (!HasKey(key) || (dictionary_[key]->GetType() != TYPE_DICTIONARY)) {
283 entry = new DictionaryValue;
284 SetInCurrentNode(key, entry);
285 } else {
286 entry = static_cast<DictionaryValue*>(dictionary_[key]);
287 }
288
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900289 std::wstring remaining_path = path.substr(delimiter_position + 1);
initial.commit3f4a7322008-07-27 06:49:38 +0900290 return entry->Set(remaining_path, in_value);
291}
292
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900293bool DictionaryValue::SetBoolean(const std::wstring& path, bool in_value) {
initial.commit3f4a7322008-07-27 06:49:38 +0900294 return Set(path, CreateBooleanValue(in_value));
295}
296
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900297bool DictionaryValue::SetInteger(const std::wstring& path, int in_value) {
initial.commit3f4a7322008-07-27 06:49:38 +0900298 return Set(path, CreateIntegerValue(in_value));
299}
300
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900301bool DictionaryValue::SetReal(const std::wstring& path, double in_value) {
initial.commit3f4a7322008-07-27 06:49:38 +0900302 return Set(path, CreateRealValue(in_value));
303}
304
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900305bool DictionaryValue::SetString(const std::wstring& path,
scherkus@chromium.org2b923e72008-12-11 10:23:17 +0900306 const std::string& in_value) {
307 return Set(path, CreateStringValue(in_value));
308}
309
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900310bool DictionaryValue::SetString(const std::wstring& path,
311 const std::wstring& in_value) {
312 return Set(path, CreateStringValue(in_value));
initial.commit3f4a7322008-07-27 06:49:38 +0900313}
314
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900315bool DictionaryValue::Get(const std::wstring& path, Value** out_value) const {
316 std::wstring key = path;
initial.commit3f4a7322008-07-27 06:49:38 +0900317
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900318 size_t delimiter_position = path.find_first_of(L".", 0);
319 if (delimiter_position != std::wstring::npos) {
initial.commit3f4a7322008-07-27 06:49:38 +0900320 key = path.substr(0, delimiter_position);
321 }
322
323 ValueMap::const_iterator entry_iterator = dictionary_.find(key);
324 if (entry_iterator == dictionary_.end())
325 return false;
326 Value* entry = entry_iterator->second;
327
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900328 if (delimiter_position == std::wstring::npos) {
initial.commit3f4a7322008-07-27 06:49:38 +0900329 if (out_value)
330 *out_value = entry;
331 return true;
332 }
333
334 if (entry->IsType(TYPE_DICTIONARY)) {
335 DictionaryValue* dictionary = static_cast<DictionaryValue*>(entry);
336 return dictionary->Get(path.substr(delimiter_position + 1), out_value);
337 }
338
339 return false;
340}
341
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900342bool DictionaryValue::GetBoolean(const std::wstring& path,
initial.commit3f4a7322008-07-27 06:49:38 +0900343 bool* bool_value) const {
344 Value* value;
345 if (!Get(path, &value))
346 return false;
347
348 return value->GetAsBoolean(bool_value);
349}
350
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900351bool DictionaryValue::GetInteger(const std::wstring& path,
initial.commit3f4a7322008-07-27 06:49:38 +0900352 int* out_value) const {
353 Value* value;
354 if (!Get(path, &value))
355 return false;
356
357 return value->GetAsInteger(out_value);
358}
359
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900360bool DictionaryValue::GetReal(const std::wstring& path,
initial.commit3f4a7322008-07-27 06:49:38 +0900361 double* out_value) const {
362 Value* value;
363 if (!Get(path, &value))
364 return false;
365
366 return value->GetAsReal(out_value);
367}
368
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900369bool DictionaryValue::GetString(const std::wstring& path,
scherkus@chromium.org2b923e72008-12-11 10:23:17 +0900370 std::string* out_value) const {
371 Value* value;
372 if (!Get(path, &value))
373 return false;
374
375 return value->GetAsString(out_value);
376}
377
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900378bool DictionaryValue::GetString(const std::wstring& path,
379 std::wstring* out_value) const {
initial.commit3f4a7322008-07-27 06:49:38 +0900380 Value* value;
381 if (!Get(path, &value))
382 return false;
383
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900384 return value->GetAsString(out_value);
initial.commit3f4a7322008-07-27 06:49:38 +0900385}
386
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900387bool DictionaryValue::GetBinary(const std::wstring& path,
initial.commit3f4a7322008-07-27 06:49:38 +0900388 BinaryValue** out_value) const {
389 Value* value;
390 bool result = Get(path, &value);
391 if (!result || !value->IsType(TYPE_BINARY))
392 return false;
393
394 if (out_value)
395 *out_value = static_cast<BinaryValue*>(value);
396
397 return true;
398}
399
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900400bool DictionaryValue::GetDictionary(const std::wstring& path,
initial.commit3f4a7322008-07-27 06:49:38 +0900401 DictionaryValue** out_value) const {
402 Value* value;
403 bool result = Get(path, &value);
404 if (!result || !value->IsType(TYPE_DICTIONARY))
405 return false;
406
407 if (out_value)
408 *out_value = static_cast<DictionaryValue*>(value);
409
410 return true;
411}
412
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900413bool DictionaryValue::GetList(const std::wstring& path,
initial.commit3f4a7322008-07-27 06:49:38 +0900414 ListValue** out_value) const {
415 Value* value;
416 bool result = Get(path, &value);
417 if (!result || !value->IsType(TYPE_LIST))
418 return false;
419
420 if (out_value)
421 *out_value = static_cast<ListValue*>(value);
422
423 return true;
424}
425
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900426bool DictionaryValue::Remove(const std::wstring& path, Value** out_value) {
427 std::wstring key = path;
initial.commit3f4a7322008-07-27 06:49:38 +0900428
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900429 size_t delimiter_position = path.find_first_of(L".", 0);
430 if (delimiter_position != std::wstring::npos) {
initial.commit3f4a7322008-07-27 06:49:38 +0900431 key = path.substr(0, delimiter_position);
432 }
433
434 ValueMap::iterator entry_iterator = dictionary_.find(key);
435 if (entry_iterator == dictionary_.end())
436 return false;
437 Value* entry = entry_iterator->second;
438
nsylvain@chromium.org12426672009-03-04 07:59:43 +0900439 if (delimiter_position == std::wstring::npos) {
initial.commit3f4a7322008-07-27 06:49:38 +0900440 if (out_value)
441 *out_value = entry;
442 else
443 delete entry;
444
445 dictionary_.erase(entry_iterator);
446 return true;
447 }
448
449 if (entry->IsType(TYPE_DICTIONARY)) {
450 DictionaryValue* dictionary = static_cast<DictionaryValue*>(entry);
451 return dictionary->Remove(path.substr(delimiter_position + 1), out_value);
452 }
453
454 return false;
455}
456
457Value* DictionaryValue::DeepCopy() const {
458 DictionaryValue* result = new DictionaryValue;
459
460 ValueMap::const_iterator current_entry = dictionary_.begin();
461 while (current_entry != dictionary_.end()) {
462 result->Set(current_entry->first, current_entry->second->DeepCopy());
463 ++current_entry;
464 }
465
466 return result;
467}
468
469bool DictionaryValue::Equals(const Value* other) const {
470 if (other->GetType() != GetType())
471 return false;
472
473 const DictionaryValue* other_dict =
474 static_cast<const DictionaryValue*>(other);
475 key_iterator lhs_it(begin_keys());
476 key_iterator rhs_it(other_dict->begin_keys());
477 while (lhs_it != end_keys() && rhs_it != other_dict->end_keys()) {
478 Value* lhs;
479 Value* rhs;
480 if (!Get(*lhs_it, &lhs) || !other_dict->Get(*rhs_it, &rhs) ||
481 !lhs->Equals(rhs)) {
482 return false;
483 }
484 ++lhs_it;
485 ++rhs_it;
486 }
487 if (lhs_it != end_keys() || rhs_it != other_dict->end_keys())
488 return false;
489
490 return true;
491}
492
493///////////////////// ListValue ////////////////////
494
495ListValue::~ListValue() {
496 Clear();
497}
498
499void ListValue::Clear() {
pkasting@chromium.org727139c2009-05-09 09:33:04 +0900500 for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i)
501 delete *i;
initial.commit3f4a7322008-07-27 06:49:38 +0900502 list_.clear();
503}
504
505bool ListValue::Set(size_t index, Value* in_value) {
506 if (!in_value)
507 return false;
508
509 if (index >= list_.size()) {
510 // Pad out any intermediate indexes with null settings
511 while (index > list_.size())
512 Append(CreateNullValue());
513 Append(in_value);
514 } else {
515 DCHECK(list_[index] != in_value);
516 delete list_[index];
517 list_[index] = in_value;
518 }
519 return true;
520}
521
522bool ListValue::Get(size_t index, Value** out_value) const {
523 if (index >= list_.size())
524 return false;
525
526 if (out_value)
527 *out_value = list_[index];
528
529 return true;
530}
531
aa@chromium.orgc93b02f2009-01-21 06:05:32 +0900532bool ListValue::GetBoolean(size_t index, bool* bool_value) const {
533 Value* value;
534 if (!Get(index, &value))
535 return false;
536
537 return value->GetAsBoolean(bool_value);
538}
539
540bool ListValue::GetInteger(size_t index, int* out_value) const {
541 Value* value;
542 if (!Get(index, &value))
543 return false;
544
545 return value->GetAsInteger(out_value);
546}
547
548bool ListValue::GetReal(size_t index, double* out_value) const {
549 Value* value;
550 if (!Get(index, &value))
551 return false;
552
553 return value->GetAsReal(out_value);
554}
555
556bool ListValue::GetString(size_t index, std::string* out_value) const {
557 Value* value;
558 if (!Get(index, &value))
559 return false;
560
561 return value->GetAsString(out_value);
562}
563
564bool ListValue::GetBinary(size_t index, BinaryValue** out_value) const {
565 Value* value;
566 bool result = Get(index, &value);
567 if (!result || !value->IsType(TYPE_BINARY))
568 return false;
569
570 if (out_value)
571 *out_value = static_cast<BinaryValue*>(value);
572
573 return true;
574}
575
576bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) const {
initial.commit3f4a7322008-07-27 06:49:38 +0900577 Value* value;
578 bool result = Get(index, &value);
579 if (!result || !value->IsType(TYPE_DICTIONARY))
580 return false;
581
582 if (out_value)
583 *out_value = static_cast<DictionaryValue*>(value);
584
585 return true;
586}
587
aa@chromium.orgc93b02f2009-01-21 06:05:32 +0900588bool ListValue::GetList(size_t index, ListValue** out_value) const {
589 Value* value;
590 bool result = Get(index, &value);
591 if (!result || !value->IsType(TYPE_LIST))
592 return false;
593
594 if (out_value)
595 *out_value = static_cast<ListValue*>(value);
596
597 return true;
598}
599
initial.commit3f4a7322008-07-27 06:49:38 +0900600bool ListValue::Remove(size_t index, Value** out_value) {
601 if (index >= list_.size())
602 return false;
603
604 if (out_value)
605 *out_value = list_[index];
606 else
607 delete list_[index];
608
pkasting@chromium.org727139c2009-05-09 09:33:04 +0900609 list_.erase(list_.begin() + index);
initial.commit3f4a7322008-07-27 06:49:38 +0900610 return true;
611}
612
erikkay@chromium.org9034a232009-08-29 05:26:05 +0900613int ListValue::Remove(const Value& value) {
pkasting@chromium.org727139c2009-05-09 09:33:04 +0900614 for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) {
615 if ((*i)->Equals(&value)) {
erikkay@chromium.org9034a232009-08-29 05:26:05 +0900616 size_t index = i - list_.begin();
pkasting@chromium.org727139c2009-05-09 09:33:04 +0900617 list_.erase(i);
erikkay@chromium.org9034a232009-08-29 05:26:05 +0900618 return index;
pkasting@chromium.org727139c2009-05-09 09:33:04 +0900619 }
620 }
erikkay@chromium.org9034a232009-08-29 05:26:05 +0900621 return -1;
pkasting@chromium.org727139c2009-05-09 09:33:04 +0900622}
623
initial.commit3f4a7322008-07-27 06:49:38 +0900624void ListValue::Append(Value* in_value) {
625 DCHECK(in_value);
626 list_.push_back(in_value);
627}
628
erikkay@chromium.org9034a232009-08-29 05:26:05 +0900629bool ListValue::Insert(size_t index, Value* in_value) {
630 DCHECK(in_value);
631 if (index < 0 || index > list_.size())
632 return false;
633
634 list_.insert(list_.begin() + index, in_value);
635 return true;
636}
637
initial.commit3f4a7322008-07-27 06:49:38 +0900638Value* ListValue::DeepCopy() const {
639 ListValue* result = new ListValue;
640
pkasting@chromium.org727139c2009-05-09 09:33:04 +0900641 for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i)
642 result->Append((*i)->DeepCopy());
initial.commit3f4a7322008-07-27 06:49:38 +0900643
644 return result;
645}
646
647bool ListValue::Equals(const Value* other) const {
648 if (other->GetType() != GetType())
649 return false;
650
651 const ListValue* other_list =
652 static_cast<const ListValue*>(other);
653 const_iterator lhs_it, rhs_it;
654 for (lhs_it = begin(), rhs_it = other_list->begin();
655 lhs_it != end() && rhs_it != other_list->end();
656 ++lhs_it, ++rhs_it) {
657 if (!(*lhs_it)->Equals(*rhs_it))
658 return false;
659 }
660 if (lhs_it != end() || rhs_it != other_list->end())
661 return false;
662
663 return true;
664}