OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/values.h" | 5 #include "base/values.h" |
6 | 6 |
7 #include <string.h> | 7 #include <string.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <cmath> | 10 #include <cmath> |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
66 | 66 |
67 case Value::Type::DICTIONARY: | 67 case Value::Type::DICTIONARY: |
68 return CopyDictionaryWithoutEmptyChildren( | 68 return CopyDictionaryWithoutEmptyChildren( |
69 static_cast<const DictionaryValue&>(node)); | 69 static_cast<const DictionaryValue&>(node)); |
70 | 70 |
71 default: | 71 default: |
72 return node.CreateDeepCopy(); | 72 return node.CreateDeepCopy(); |
73 } | 73 } |
74 } | 74 } |
75 | 75 |
76 // TODO(crbug.com/646113): Remove this once all types are implemented. | |
77 bool IsAssignmentSafe(Value::Type lhs, Value::Type rhs) { | |
78 auto IsImplemented = [](Value::Type type) { | |
79 return type == Value::Type::NONE || type == Value::Type::BOOLEAN || | |
80 type == Value::Type::INTEGER || type == Value::Type::DOUBLE || | |
81 type == Value::Type::STRING || type == Value::Type::BINARY; | |
82 }; | |
83 | |
84 return lhs == rhs || (IsImplemented(lhs) && IsImplemented(rhs)); | |
85 } | |
86 | |
87 } // namespace | 76 } // namespace |
88 | 77 |
89 // static | 78 // static |
90 std::unique_ptr<Value> Value::CreateNullValue() { | 79 std::unique_ptr<Value> Value::CreateNullValue() { |
91 return WrapUnique(new Value(Type::NONE)); | 80 return WrapUnique(new Value(Type::NONE)); |
92 } | 81 } |
93 | 82 |
94 // static | 83 // static |
95 std::unique_ptr<BinaryValue> BinaryValue::CreateWithCopiedBuffer( | 84 std::unique_ptr<BinaryValue> BinaryValue::CreateWithCopiedBuffer( |
96 const char* buffer, | 85 const char* buffer, |
(...skipping 25 matching lines...) Expand all Loading... | |
122 return; | 111 return; |
123 case Type::DOUBLE: | 112 case Type::DOUBLE: |
124 double_value_ = 0.0; | 113 double_value_ = 0.0; |
125 return; | 114 return; |
126 case Type::STRING: | 115 case Type::STRING: |
127 string_value_.Init(); | 116 string_value_.Init(); |
128 return; | 117 return; |
129 case Type::BINARY: | 118 case Type::BINARY: |
130 binary_value_.Init(); | 119 binary_value_.Init(); |
131 return; | 120 return; |
132 | 121 case Type::DICTIONARY: |
133 // TODO(crbug.com/646113): Implement these once the corresponding derived | 122 dict_ptr_.Init(MakeUnique<DictStorage>()); |
134 // classes are removed. | 123 return; |
135 case Type::LIST: | 124 case Type::LIST: |
136 case Type::DICTIONARY: | 125 list_.Init(); |
137 return; | 126 return; |
138 } | 127 } |
139 } | 128 } |
140 | 129 |
141 Value::Value(bool in_bool) : type_(Type::BOOLEAN), bool_value_(in_bool) {} | 130 Value::Value(bool in_bool) : type_(Type::BOOLEAN), bool_value_(in_bool) {} |
142 | 131 |
143 Value::Value(int in_int) : type_(Type::INTEGER), int_value_(in_int) {} | 132 Value::Value(int in_int) : type_(Type::INTEGER), int_value_(in_int) {} |
144 | 133 |
145 Value::Value(double in_double) : type_(Type::DOUBLE), double_value_(in_double) { | 134 Value::Value(double in_double) : type_(Type::DOUBLE), double_value_(in_double) { |
146 if (!std::isfinite(double_value_)) { | 135 if (!std::isfinite(double_value_)) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 Value::Value(const std::vector<char>& in_blob) : type_(Type::BINARY) { | 167 Value::Value(const std::vector<char>& in_blob) : type_(Type::BINARY) { |
179 binary_value_.Init(in_blob); | 168 binary_value_.Init(in_blob); |
180 } | 169 } |
181 | 170 |
182 Value::Value(std::vector<char>&& in_blob) : type_(Type::BINARY) { | 171 Value::Value(std::vector<char>&& in_blob) : type_(Type::BINARY) { |
183 binary_value_.Init(std::move(in_blob)); | 172 binary_value_.Init(std::move(in_blob)); |
184 } | 173 } |
185 | 174 |
186 Value& Value::operator=(const Value& that) { | 175 Value& Value::operator=(const Value& that) { |
187 if (this != &that) { | 176 if (this != &that) { |
188 DCHECK(IsAssignmentSafe(type_, that.type_)); | |
189 if (type_ == that.type_) { | 177 if (type_ == that.type_) { |
190 InternalCopyAssignFrom(that); | 178 InternalCopyAssignFrom(that); |
191 } else { | 179 } else { |
192 InternalCleanup(); | 180 InternalCleanup(); |
193 InternalCopyConstructFrom(that); | 181 InternalCopyConstructFrom(that); |
194 } | 182 } |
195 } | 183 } |
196 | 184 |
197 return *this; | 185 return *this; |
198 } | 186 } |
199 | 187 |
200 Value& Value::operator=(Value&& that) { | 188 Value& Value::operator=(Value&& that) { |
201 if (this != &that) { | 189 if (this != &that) { |
202 DCHECK(IsAssignmentSafe(type_, that.type_)); | |
203 if (type_ == that.type_) { | 190 if (type_ == that.type_) { |
204 InternalMoveAssignFrom(std::move(that)); | 191 InternalMoveAssignFrom(std::move(that)); |
205 } else { | 192 } else { |
206 InternalCleanup(); | 193 InternalCleanup(); |
207 InternalMoveConstructFrom(std::move(that)); | 194 InternalMoveConstructFrom(std::move(that)); |
208 } | 195 } |
209 } | 196 } |
210 | 197 |
211 return *this; | 198 return *this; |
212 } | 199 } |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
321 | 308 |
322 bool Value::GetAsBinary(const BinaryValue** out_value) const { | 309 bool Value::GetAsBinary(const BinaryValue** out_value) const { |
323 if (out_value && is_blob()) { | 310 if (out_value && is_blob()) { |
324 *out_value = this; | 311 *out_value = this; |
325 return true; | 312 return true; |
326 } | 313 } |
327 return is_blob(); | 314 return is_blob(); |
328 } | 315 } |
329 | 316 |
330 bool Value::GetAsList(ListValue** out_value) { | 317 bool Value::GetAsList(ListValue** out_value) { |
331 return false; | 318 if (out_value && is_list()) { |
319 *out_value = static_cast<ListValue*>(this); | |
320 return true; | |
321 } | |
322 return is_list(); | |
332 } | 323 } |
333 | 324 |
334 bool Value::GetAsList(const ListValue** out_value) const { | 325 bool Value::GetAsList(const ListValue** out_value) const { |
335 return false; | 326 if (out_value && is_list()) { |
327 *out_value = static_cast<const ListValue*>(this); | |
328 return true; | |
329 } | |
330 return is_list(); | |
336 } | 331 } |
337 | 332 |
338 bool Value::GetAsDictionary(DictionaryValue** out_value) { | 333 bool Value::GetAsDictionary(DictionaryValue** out_value) { |
339 return false; | 334 if (out_value && is_dict()) { |
335 *out_value = static_cast<DictionaryValue*>(this); | |
336 return true; | |
337 } | |
338 return is_dict(); | |
340 } | 339 } |
341 | 340 |
342 bool Value::GetAsDictionary(const DictionaryValue** out_value) const { | 341 bool Value::GetAsDictionary(const DictionaryValue** out_value) const { |
343 return false; | 342 if (out_value && is_dict()) { |
343 *out_value = static_cast<const DictionaryValue*>(this); | |
344 return true; | |
345 } | |
346 return is_dict(); | |
344 } | 347 } |
345 | 348 |
346 Value* Value::DeepCopy() const { | 349 Value* Value::DeepCopy() const { |
347 // This method should only be getting called for null Values--all subclasses | 350 // This method should only be getting called for null Values--all subclasses |
348 // need to provide their own implementation;. | 351 // need to provide their own implementation;. |
349 switch (type()) { | 352 switch (type()) { |
350 case Type::NONE: | 353 case Type::NONE: |
351 return CreateNullValue().release(); | 354 return CreateNullValue().release(); |
352 | 355 |
353 // For now, make FundamentalValues for backward-compatibility. Convert to | 356 // For now, make FundamentalValues for backward-compatibility. Convert to |
354 // Value when that code is deleted. | 357 // Value when that code is deleted. |
355 case Type::BOOLEAN: | 358 case Type::BOOLEAN: |
356 return new FundamentalValue(bool_value_); | 359 return new FundamentalValue(bool_value_); |
357 case Type::INTEGER: | 360 case Type::INTEGER: |
358 return new FundamentalValue(int_value_); | 361 return new FundamentalValue(int_value_); |
359 case Type::DOUBLE: | 362 case Type::DOUBLE: |
360 return new FundamentalValue(double_value_); | 363 return new FundamentalValue(double_value_); |
361 // For now, make StringValues for backward-compatibility. Convert to | 364 // For now, make StringValues for backward-compatibility. Convert to |
362 // Value when that code is deleted. | 365 // Value when that code is deleted. |
363 case Type::STRING: | 366 case Type::STRING: |
364 return new StringValue(*string_value_); | 367 return new StringValue(*string_value_); |
365 // For now, make BinaryValues for backward-compatibility. Convert to | 368 // For now, make BinaryValues for backward-compatibility. Convert to |
366 // Value when that code is deleted. | 369 // Value when that code is deleted. |
367 case Type::BINARY: | 370 case Type::BINARY: |
368 return new BinaryValue(*binary_value_); | 371 return new BinaryValue(*binary_value_); |
369 | 372 |
373 // TODO(crbug.com/646113): Clean this up when DictionaryValue and ListValue | |
374 // are completely inlined. | |
375 case Type::DICTIONARY: { | |
376 DictionaryValue* result = new DictionaryValue; | |
377 | |
378 for (const auto& current_entry : **dict_ptr_) { | |
379 result->SetWithoutPathExpansion(current_entry.first, | |
380 current_entry.second->CreateDeepCopy()); | |
381 } | |
382 | |
383 return result; | |
384 } | |
385 | |
386 case Type::LIST: { | |
387 ListValue* result = new ListValue; | |
388 | |
389 for (const auto& entry : *list_) | |
390 result->Append(entry->CreateDeepCopy()); | |
391 | |
392 return result; | |
393 } | |
394 | |
370 default: | 395 default: |
371 // All other types should be handled by subclasses. | |
372 NOTREACHED(); | 396 NOTREACHED(); |
373 return nullptr; | 397 return nullptr; |
374 } | 398 } |
375 } | 399 } |
376 | 400 |
377 std::unique_ptr<Value> Value::CreateDeepCopy() const { | 401 std::unique_ptr<Value> Value::CreateDeepCopy() const { |
378 return WrapUnique(DeepCopy()); | 402 return WrapUnique(DeepCopy()); |
379 } | 403 } |
380 | 404 |
381 bool Value::Equals(const Value* other) const { | 405 bool Value::Equals(const Value* other) const { |
382 if (other->type() != type()) | 406 if (other->type() != type()) |
383 return false; | 407 return false; |
384 | 408 |
385 switch (type()) { | 409 switch (type()) { |
386 case Type::NONE: | 410 case Type::NONE: |
387 return true; | 411 return true; |
388 case Type::BOOLEAN: | 412 case Type::BOOLEAN: |
389 return bool_value_ == other->bool_value_; | 413 return bool_value_ == other->bool_value_; |
390 case Type::INTEGER: | 414 case Type::INTEGER: |
391 return int_value_ == other->int_value_; | 415 return int_value_ == other->int_value_; |
392 case Type::DOUBLE: | 416 case Type::DOUBLE: |
393 return double_value_ == other->double_value_; | 417 return double_value_ == other->double_value_; |
394 case Type::STRING: | 418 case Type::STRING: |
395 return *string_value_ == *(other->string_value_); | 419 return *string_value_ == *(other->string_value_); |
396 case Type::BINARY: | 420 case Type::BINARY: |
397 return *binary_value_ == *(other->binary_value_); | 421 return *binary_value_ == *(other->binary_value_); |
398 default: | 422 // TODO(crbug.com/646113): Clean this up when DictionaryValue and ListValue |
399 // This method should only be getting called for the above types -- all | 423 // are completely inlined. |
400 // subclasses need to provide their own implementation;. | 424 case Type::DICTIONARY: { |
401 NOTREACHED(); | 425 if ((*dict_ptr_)->size() != (*other->dict_ptr_)->size()) |
402 return false; | 426 return false; |
427 | |
428 return std::equal(std::begin(**dict_ptr_), std::end(**dict_ptr_), | |
429 std::begin(**(other->dict_ptr_)), | |
430 [](const DictStorage::value_type& lhs, | |
431 const DictStorage::value_type& rhs) { | |
432 if (lhs.first != rhs.first) | |
433 return false; | |
434 | |
435 return lhs.second->Equals(rhs.second.get()); | |
436 }); | |
437 } | |
438 case Type::LIST: { | |
439 if (list_->size() != other->list_->size()) | |
440 return false; | |
441 | |
442 return std::equal(std::begin(*list_), std::end(*list_), | |
443 std::begin(*(other->list_)), | |
444 [](const ListStorage::value_type& lhs, | |
445 const ListStorage::value_type& rhs) { | |
446 return lhs->Equals(rhs.get()); | |
447 }); | |
448 } | |
403 } | 449 } |
450 | |
451 NOTREACHED(); | |
452 return false; | |
404 } | 453 } |
405 | 454 |
406 // static | 455 // static |
407 bool Value::Equals(const Value* a, const Value* b) { | 456 bool Value::Equals(const Value* a, const Value* b) { |
408 if ((a == NULL) && (b == NULL)) return true; | 457 if ((a == NULL) && (b == NULL)) return true; |
409 if ((a == NULL) ^ (b == NULL)) return false; | 458 if ((a == NULL) ^ (b == NULL)) return false; |
410 return a->Equals(b); | 459 return a->Equals(b); |
411 } | 460 } |
412 | 461 |
413 void Value::InternalCopyFundamentalValue(const Value& that) { | 462 void Value::InternalCopyFundamentalValue(const Value& that) { |
(...skipping 27 matching lines...) Expand all Loading... | |
441 case Type::DOUBLE: | 490 case Type::DOUBLE: |
442 InternalCopyFundamentalValue(that); | 491 InternalCopyFundamentalValue(that); |
443 return; | 492 return; |
444 | 493 |
445 case Type::STRING: | 494 case Type::STRING: |
446 string_value_.Init(*that.string_value_); | 495 string_value_.Init(*that.string_value_); |
447 return; | 496 return; |
448 case Type::BINARY: | 497 case Type::BINARY: |
449 binary_value_.Init(*that.binary_value_); | 498 binary_value_.Init(*that.binary_value_); |
450 return; | 499 return; |
451 | 500 // DictStorage and ListStorage are move-only types due to the presence of |
brettw
2017/02/15 21:28:29
I think this comment is out-of-date now.
jdoerrie
2017/02/16 09:19:35
I think it's still relevant. DictStorage and ListS
| |
452 // TODO(crbug.com/646113): Implement these once the corresponding derived | 501 // unique_ptrs. This is why the call to |CreateDeepCopy| is necessary here. |
453 // classes are removed. | 502 // TODO(crbug.com/646113): Clean this up when DictStorage and ListStorage |
503 // can be copied directly. | |
504 case Type::DICTIONARY: | |
505 dict_ptr_.Init(std::move(*that.CreateDeepCopy()->dict_ptr_)); | |
506 return; | |
454 case Type::LIST: | 507 case Type::LIST: |
455 case Type::DICTIONARY: | 508 list_.Init(std::move(*that.CreateDeepCopy()->list_)); |
456 return; | 509 return; |
457 } | 510 } |
458 } | 511 } |
459 | 512 |
460 void Value::InternalMoveConstructFrom(Value&& that) { | 513 void Value::InternalMoveConstructFrom(Value&& that) { |
461 type_ = that.type_; | 514 type_ = that.type_; |
462 | 515 |
463 switch (type_) { | 516 switch (type_) { |
464 case Type::NONE: | 517 case Type::NONE: |
465 case Type::BOOLEAN: | 518 case Type::BOOLEAN: |
466 case Type::INTEGER: | 519 case Type::INTEGER: |
467 case Type::DOUBLE: | 520 case Type::DOUBLE: |
468 InternalCopyFundamentalValue(that); | 521 InternalCopyFundamentalValue(that); |
469 return; | 522 return; |
470 | 523 |
471 case Type::STRING: | 524 case Type::STRING: |
472 string_value_.InitFromMove(std::move(that.string_value_)); | 525 string_value_.InitFromMove(std::move(that.string_value_)); |
473 return; | 526 return; |
474 case Type::BINARY: | 527 case Type::BINARY: |
475 binary_value_.InitFromMove(std::move(that.binary_value_)); | 528 binary_value_.InitFromMove(std::move(that.binary_value_)); |
476 return; | 529 return; |
477 | 530 case Type::DICTIONARY: |
478 // TODO(crbug.com/646113): Implement these once the corresponding derived | 531 dict_ptr_.InitFromMove(std::move(that.dict_ptr_)); |
479 // classes are removed. | 532 return; |
480 case Type::LIST: | 533 case Type::LIST: |
481 case Type::DICTIONARY: | 534 list_.InitFromMove(std::move(that.list_)); |
482 return; | 535 return; |
483 } | 536 } |
484 } | 537 } |
485 | 538 |
486 void Value::InternalCopyAssignFrom(const Value& that) { | 539 void Value::InternalCopyAssignFrom(const Value& that) { |
487 type_ = that.type_; | 540 type_ = that.type_; |
488 | 541 |
489 switch (type_) { | 542 switch (type_) { |
490 case Type::NONE: | 543 case Type::NONE: |
491 case Type::BOOLEAN: | 544 case Type::BOOLEAN: |
492 case Type::INTEGER: | 545 case Type::INTEGER: |
493 case Type::DOUBLE: | 546 case Type::DOUBLE: |
494 InternalCopyFundamentalValue(that); | 547 InternalCopyFundamentalValue(that); |
495 return; | 548 return; |
496 | 549 |
497 case Type::STRING: | 550 case Type::STRING: |
498 *string_value_ = *that.string_value_; | 551 *string_value_ = *that.string_value_; |
499 return; | 552 return; |
500 case Type::BINARY: | 553 case Type::BINARY: |
501 *binary_value_ = *that.binary_value_; | 554 *binary_value_ = *that.binary_value_; |
502 return; | 555 return; |
503 | 556 // DictStorage and ListStorage are move-only types due to the presence of |
brettw
2017/02/15 21:28:29
Ditto
jdoerrie
2017/02/16 09:19:35
Same as above (s/copy constructor/copy assignment
| |
504 // TODO(crbug.com/646113): Implement these once the corresponding derived | 557 // unique_ptrs. This is why the call to |CreateDeepCopy| is necessary here. |
505 // classes are removed. | 558 // TODO(crbug.com/646113): Clean this up when DictStorage and ListStorage |
559 // can be copied directly. | |
560 case Type::DICTIONARY: | |
561 *dict_ptr_ = std::move(*that.CreateDeepCopy()->dict_ptr_); | |
562 return; | |
506 case Type::LIST: | 563 case Type::LIST: |
507 case Type::DICTIONARY: | 564 *list_ = std::move(*that.CreateDeepCopy()->list_); |
508 return; | 565 return; |
509 } | 566 } |
510 } | 567 } |
511 | 568 |
512 void Value::InternalMoveAssignFrom(Value&& that) { | 569 void Value::InternalMoveAssignFrom(Value&& that) { |
513 type_ = that.type_; | 570 type_ = that.type_; |
514 | 571 |
515 switch (type_) { | 572 switch (type_) { |
516 case Type::NONE: | 573 case Type::NONE: |
517 case Type::BOOLEAN: | 574 case Type::BOOLEAN: |
518 case Type::INTEGER: | 575 case Type::INTEGER: |
519 case Type::DOUBLE: | 576 case Type::DOUBLE: |
520 InternalCopyFundamentalValue(that); | 577 InternalCopyFundamentalValue(that); |
521 return; | 578 return; |
522 | 579 |
523 case Type::STRING: | 580 case Type::STRING: |
524 *string_value_ = std::move(*that.string_value_); | 581 *string_value_ = std::move(*that.string_value_); |
525 return; | 582 return; |
526 case Type::BINARY: | 583 case Type::BINARY: |
527 *binary_value_ = std::move(*that.binary_value_); | 584 *binary_value_ = std::move(*that.binary_value_); |
528 return; | 585 return; |
529 | 586 case Type::DICTIONARY: |
530 // TODO(crbug.com/646113): Implement these once the corresponding derived | 587 *dict_ptr_ = std::move(*that.dict_ptr_); |
531 // classes are removed. | 588 return; |
532 case Type::LIST: | 589 case Type::LIST: |
533 case Type::DICTIONARY: | 590 *list_ = std::move(*that.list_); |
534 return; | 591 return; |
535 } | 592 } |
536 } | 593 } |
537 | 594 |
538 void Value::InternalCleanup() { | 595 void Value::InternalCleanup() { |
539 switch (type_) { | 596 switch (type_) { |
540 case Type::NONE: | 597 case Type::NONE: |
541 case Type::BOOLEAN: | 598 case Type::BOOLEAN: |
542 case Type::INTEGER: | 599 case Type::INTEGER: |
543 case Type::DOUBLE: | 600 case Type::DOUBLE: |
544 // Nothing to do | 601 // Nothing to do |
545 return; | 602 return; |
546 | 603 |
547 case Type::STRING: | 604 case Type::STRING: |
548 string_value_.Destroy(); | 605 string_value_.Destroy(); |
549 return; | 606 return; |
550 case Type::BINARY: | 607 case Type::BINARY: |
551 binary_value_.Destroy(); | 608 binary_value_.Destroy(); |
552 return; | 609 return; |
553 | 610 case Type::DICTIONARY: |
554 // TODO(crbug.com/646113): Implement these once the corresponding derived | 611 dict_ptr_.Destroy(); |
555 // classes are removed. | 612 return; |
556 case Type::LIST: | 613 case Type::LIST: |
557 case Type::DICTIONARY: | 614 list_.Destroy(); |
558 return; | 615 return; |
559 } | 616 } |
560 } | 617 } |
561 | 618 |
562 ///////////////////// DictionaryValue //////////////////// | 619 ///////////////////// DictionaryValue //////////////////// |
563 | 620 |
564 // static | 621 // static |
565 std::unique_ptr<DictionaryValue> DictionaryValue::From( | 622 std::unique_ptr<DictionaryValue> DictionaryValue::From( |
566 std::unique_ptr<Value> value) { | 623 std::unique_ptr<Value> value) { |
567 DictionaryValue* out; | 624 DictionaryValue* out; |
568 if (value && value->GetAsDictionary(&out)) { | 625 if (value && value->GetAsDictionary(&out)) { |
569 ignore_result(value.release()); | 626 ignore_result(value.release()); |
570 return WrapUnique(out); | 627 return WrapUnique(out); |
571 } | 628 } |
572 return nullptr; | 629 return nullptr; |
573 } | 630 } |
574 | 631 |
575 DictionaryValue::DictionaryValue() : Value(Type::DICTIONARY) {} | 632 DictionaryValue::DictionaryValue() : Value(Type::DICTIONARY) {} |
576 | 633 |
577 DictionaryValue::~DictionaryValue() { | |
578 Clear(); | |
579 } | |
580 | |
581 bool DictionaryValue::GetAsDictionary(DictionaryValue** out_value) { | |
582 if (out_value) | |
583 *out_value = this; | |
584 return true; | |
585 } | |
586 | |
587 bool DictionaryValue::GetAsDictionary(const DictionaryValue** out_value) const { | |
588 if (out_value) | |
589 *out_value = this; | |
590 return true; | |
591 } | |
592 | |
593 bool DictionaryValue::HasKey(StringPiece key) const { | 634 bool DictionaryValue::HasKey(StringPiece key) const { |
594 DCHECK(IsStringUTF8(key)); | 635 DCHECK(IsStringUTF8(key)); |
595 auto current_entry = dictionary_.find(key.as_string()); | 636 auto current_entry = (*dict_ptr_)->find(key.as_string()); |
596 DCHECK((current_entry == dictionary_.end()) || current_entry->second); | 637 DCHECK((current_entry == (*dict_ptr_)->end()) || current_entry->second); |
597 return current_entry != dictionary_.end(); | 638 return current_entry != (*dict_ptr_)->end(); |
598 } | 639 } |
599 | 640 |
600 void DictionaryValue::Clear() { | 641 void DictionaryValue::Clear() { |
601 dictionary_.clear(); | 642 (*dict_ptr_)->clear(); |
602 } | 643 } |
603 | 644 |
604 void DictionaryValue::Set(StringPiece path, std::unique_ptr<Value> in_value) { | 645 void DictionaryValue::Set(StringPiece path, std::unique_ptr<Value> in_value) { |
605 DCHECK(IsStringUTF8(path)); | 646 DCHECK(IsStringUTF8(path)); |
606 DCHECK(in_value); | 647 DCHECK(in_value); |
607 | 648 |
608 StringPiece current_path(path); | 649 StringPiece current_path(path); |
609 DictionaryValue* current_dictionary = this; | 650 DictionaryValue* current_dictionary = this; |
610 for (size_t delimiter_position = current_path.find('.'); | 651 for (size_t delimiter_position = current_path.find('.'); |
611 delimiter_position != StringPiece::npos; | 652 delimiter_position != StringPiece::npos; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
646 void DictionaryValue::SetString(StringPiece path, StringPiece in_value) { | 687 void DictionaryValue::SetString(StringPiece path, StringPiece in_value) { |
647 Set(path, new StringValue(in_value)); | 688 Set(path, new StringValue(in_value)); |
648 } | 689 } |
649 | 690 |
650 void DictionaryValue::SetString(StringPiece path, const string16& in_value) { | 691 void DictionaryValue::SetString(StringPiece path, const string16& in_value) { |
651 Set(path, new StringValue(in_value)); | 692 Set(path, new StringValue(in_value)); |
652 } | 693 } |
653 | 694 |
654 void DictionaryValue::SetWithoutPathExpansion(StringPiece key, | 695 void DictionaryValue::SetWithoutPathExpansion(StringPiece key, |
655 std::unique_ptr<Value> in_value) { | 696 std::unique_ptr<Value> in_value) { |
656 dictionary_[key.as_string()] = std::move(in_value); | 697 (**dict_ptr_)[key.as_string()] = std::move(in_value); |
657 } | 698 } |
658 | 699 |
659 void DictionaryValue::SetWithoutPathExpansion(StringPiece key, | 700 void DictionaryValue::SetWithoutPathExpansion(StringPiece key, |
660 Value* in_value) { | 701 Value* in_value) { |
661 SetWithoutPathExpansion(key, WrapUnique(in_value)); | 702 SetWithoutPathExpansion(key, WrapUnique(in_value)); |
662 } | 703 } |
663 | 704 |
664 void DictionaryValue::SetBooleanWithoutPathExpansion(StringPiece path, | 705 void DictionaryValue::SetBooleanWithoutPathExpansion(StringPiece path, |
665 bool in_value) { | 706 bool in_value) { |
666 SetWithoutPathExpansion(path, | 707 SetWithoutPathExpansion(path, |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
826 | 867 |
827 bool DictionaryValue::GetList(StringPiece path, ListValue** out_value) { | 868 bool DictionaryValue::GetList(StringPiece path, ListValue** out_value) { |
828 return static_cast<const DictionaryValue&>(*this).GetList( | 869 return static_cast<const DictionaryValue&>(*this).GetList( |
829 path, | 870 path, |
830 const_cast<const ListValue**>(out_value)); | 871 const_cast<const ListValue**>(out_value)); |
831 } | 872 } |
832 | 873 |
833 bool DictionaryValue::GetWithoutPathExpansion(StringPiece key, | 874 bool DictionaryValue::GetWithoutPathExpansion(StringPiece key, |
834 const Value** out_value) const { | 875 const Value** out_value) const { |
835 DCHECK(IsStringUTF8(key)); | 876 DCHECK(IsStringUTF8(key)); |
836 auto entry_iterator = dictionary_.find(key.as_string()); | 877 auto entry_iterator = (*dict_ptr_)->find(key.as_string()); |
837 if (entry_iterator == dictionary_.end()) | 878 if (entry_iterator == (*dict_ptr_)->end()) |
838 return false; | 879 return false; |
839 | 880 |
840 if (out_value) | 881 if (out_value) |
841 *out_value = entry_iterator->second.get(); | 882 *out_value = entry_iterator->second.get(); |
842 return true; | 883 return true; |
843 } | 884 } |
844 | 885 |
845 bool DictionaryValue::GetWithoutPathExpansion(StringPiece key, | 886 bool DictionaryValue::GetWithoutPathExpansion(StringPiece key, |
846 Value** out_value) { | 887 Value** out_value) { |
847 return static_cast<const DictionaryValue&>(*this).GetWithoutPathExpansion( | 888 return static_cast<const DictionaryValue&>(*this).GetWithoutPathExpansion( |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
955 } | 996 } |
956 | 997 |
957 return current_dictionary->RemoveWithoutPathExpansion(current_path, | 998 return current_dictionary->RemoveWithoutPathExpansion(current_path, |
958 out_value); | 999 out_value); |
959 } | 1000 } |
960 | 1001 |
961 bool DictionaryValue::RemoveWithoutPathExpansion( | 1002 bool DictionaryValue::RemoveWithoutPathExpansion( |
962 StringPiece key, | 1003 StringPiece key, |
963 std::unique_ptr<Value>* out_value) { | 1004 std::unique_ptr<Value>* out_value) { |
964 DCHECK(IsStringUTF8(key)); | 1005 DCHECK(IsStringUTF8(key)); |
965 auto entry_iterator = dictionary_.find(key.as_string()); | 1006 auto entry_iterator = (*dict_ptr_)->find(key.as_string()); |
966 if (entry_iterator == dictionary_.end()) | 1007 if (entry_iterator == (*dict_ptr_)->end()) |
967 return false; | 1008 return false; |
968 | 1009 |
969 if (out_value) | 1010 if (out_value) |
970 *out_value = std::move(entry_iterator->second); | 1011 *out_value = std::move(entry_iterator->second); |
971 dictionary_.erase(entry_iterator); | 1012 (*dict_ptr_)->erase(entry_iterator); |
972 return true; | 1013 return true; |
973 } | 1014 } |
974 | 1015 |
975 bool DictionaryValue::RemovePath(StringPiece path, | 1016 bool DictionaryValue::RemovePath(StringPiece path, |
976 std::unique_ptr<Value>* out_value) { | 1017 std::unique_ptr<Value>* out_value) { |
977 bool result = false; | 1018 bool result = false; |
978 size_t delimiter_position = path.find('.'); | 1019 size_t delimiter_position = path.find('.'); |
979 | 1020 |
980 if (delimiter_position == std::string::npos) | 1021 if (delimiter_position == std::string::npos) |
981 return RemoveWithoutPathExpansion(path, out_value); | 1022 return RemoveWithoutPathExpansion(path, out_value); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1013 continue; | 1054 continue; |
1014 } | 1055 } |
1015 } | 1056 } |
1016 // All other cases: Make a copy and hook it up. | 1057 // All other cases: Make a copy and hook it up. |
1017 SetWithoutPathExpansion(it.key(), | 1058 SetWithoutPathExpansion(it.key(), |
1018 base::WrapUnique(merge_value->DeepCopy())); | 1059 base::WrapUnique(merge_value->DeepCopy())); |
1019 } | 1060 } |
1020 } | 1061 } |
1021 | 1062 |
1022 void DictionaryValue::Swap(DictionaryValue* other) { | 1063 void DictionaryValue::Swap(DictionaryValue* other) { |
1023 dictionary_.swap(other->dictionary_); | 1064 dict_ptr_->swap(*(other->dict_ptr_)); |
1024 } | 1065 } |
1025 | 1066 |
1026 DictionaryValue::Iterator::Iterator(const DictionaryValue& target) | 1067 DictionaryValue::Iterator::Iterator(const DictionaryValue& target) |
1027 : target_(target), | 1068 : target_(target), it_((*target.dict_ptr_)->begin()) {} |
1028 it_(target.dictionary_.begin()) {} | |
1029 | 1069 |
1030 DictionaryValue::Iterator::Iterator(const Iterator& other) = default; | 1070 DictionaryValue::Iterator::Iterator(const Iterator& other) = default; |
1031 | 1071 |
1032 DictionaryValue::Iterator::~Iterator() {} | 1072 DictionaryValue::Iterator::~Iterator() {} |
1033 | 1073 |
1034 DictionaryValue* DictionaryValue::DeepCopy() const { | 1074 DictionaryValue* DictionaryValue::DeepCopy() const { |
1035 DictionaryValue* result = new DictionaryValue; | 1075 return static_cast<DictionaryValue*>(Value::DeepCopy()); |
1036 | |
1037 for (const auto& current_entry : dictionary_) { | |
1038 result->SetWithoutPathExpansion(current_entry.first, | |
1039 current_entry.second->CreateDeepCopy()); | |
1040 } | |
1041 | |
1042 return result; | |
1043 } | 1076 } |
1044 | 1077 |
1045 std::unique_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const { | 1078 std::unique_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const { |
1046 return WrapUnique(DeepCopy()); | 1079 return WrapUnique(DeepCopy()); |
1047 } | 1080 } |
1048 | 1081 |
1049 bool DictionaryValue::Equals(const Value* other) const { | |
1050 if (other->GetType() != GetType()) | |
1051 return false; | |
1052 | |
1053 const DictionaryValue* other_dict = | |
1054 static_cast<const DictionaryValue*>(other); | |
1055 Iterator lhs_it(*this); | |
1056 Iterator rhs_it(*other_dict); | |
1057 while (!lhs_it.IsAtEnd() && !rhs_it.IsAtEnd()) { | |
1058 if (lhs_it.key() != rhs_it.key() || | |
1059 !lhs_it.value().Equals(&rhs_it.value())) { | |
1060 return false; | |
1061 } | |
1062 lhs_it.Advance(); | |
1063 rhs_it.Advance(); | |
1064 } | |
1065 if (!lhs_it.IsAtEnd() || !rhs_it.IsAtEnd()) | |
1066 return false; | |
1067 | |
1068 return true; | |
1069 } | |
1070 | |
1071 ///////////////////// ListValue //////////////////// | 1082 ///////////////////// ListValue //////////////////// |
1072 | 1083 |
1073 // static | 1084 // static |
1074 std::unique_ptr<ListValue> ListValue::From(std::unique_ptr<Value> value) { | 1085 std::unique_ptr<ListValue> ListValue::From(std::unique_ptr<Value> value) { |
1075 ListValue* out; | 1086 ListValue* out; |
1076 if (value && value->GetAsList(&out)) { | 1087 if (value && value->GetAsList(&out)) { |
1077 ignore_result(value.release()); | 1088 ignore_result(value.release()); |
1078 return WrapUnique(out); | 1089 return WrapUnique(out); |
1079 } | 1090 } |
1080 return nullptr; | 1091 return nullptr; |
1081 } | 1092 } |
1082 | 1093 |
1083 ListValue::ListValue() : Value(Type::LIST) {} | 1094 ListValue::ListValue() : Value(Type::LIST) {} |
1084 | 1095 |
1085 ListValue::~ListValue() { | |
1086 Clear(); | |
1087 } | |
1088 | |
1089 void ListValue::Clear() { | 1096 void ListValue::Clear() { |
1090 list_.clear(); | 1097 list_->clear(); |
1091 } | 1098 } |
1092 | 1099 |
1093 bool ListValue::Set(size_t index, Value* in_value) { | 1100 bool ListValue::Set(size_t index, Value* in_value) { |
1094 return Set(index, WrapUnique(in_value)); | 1101 return Set(index, WrapUnique(in_value)); |
1095 } | 1102 } |
1096 | 1103 |
1097 bool ListValue::Set(size_t index, std::unique_ptr<Value> in_value) { | 1104 bool ListValue::Set(size_t index, std::unique_ptr<Value> in_value) { |
1098 if (!in_value) | 1105 if (!in_value) |
1099 return false; | 1106 return false; |
1100 | 1107 |
1101 if (index >= list_.size()) { | 1108 if (index >= list_->size()) { |
1102 // Pad out any intermediate indexes with null settings | 1109 // Pad out any intermediate indexes with null settings |
1103 while (index > list_.size()) | 1110 while (index > list_->size()) |
1104 Append(CreateNullValue()); | 1111 Append(CreateNullValue()); |
1105 Append(std::move(in_value)); | 1112 Append(std::move(in_value)); |
1106 } else { | 1113 } else { |
1107 // TODO(dcheng): remove this DCHECK once the raw pointer version is removed? | 1114 // TODO(dcheng): remove this DCHECK once the raw pointer version is removed? |
1108 DCHECK(list_[index] != in_value); | 1115 DCHECK((*list_)[index] != in_value); |
1109 list_[index] = std::move(in_value); | 1116 (*list_)[index] = std::move(in_value); |
1110 } | 1117 } |
1111 return true; | 1118 return true; |
1112 } | 1119 } |
1113 | 1120 |
1114 bool ListValue::Get(size_t index, const Value** out_value) const { | 1121 bool ListValue::Get(size_t index, const Value** out_value) const { |
1115 if (index >= list_.size()) | 1122 if (index >= list_->size()) |
1116 return false; | 1123 return false; |
1117 | 1124 |
1118 if (out_value) | 1125 if (out_value) |
1119 *out_value = list_[index].get(); | 1126 *out_value = (*list_)[index].get(); |
1120 | 1127 |
1121 return true; | 1128 return true; |
1122 } | 1129 } |
1123 | 1130 |
1124 bool ListValue::Get(size_t index, Value** out_value) { | 1131 bool ListValue::Get(size_t index, Value** out_value) { |
1125 return static_cast<const ListValue&>(*this).Get( | 1132 return static_cast<const ListValue&>(*this).Get( |
1126 index, | 1133 index, |
1127 const_cast<const Value**>(out_value)); | 1134 const_cast<const Value**>(out_value)); |
1128 } | 1135 } |
1129 | 1136 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1216 return true; | 1223 return true; |
1217 } | 1224 } |
1218 | 1225 |
1219 bool ListValue::GetList(size_t index, ListValue** out_value) { | 1226 bool ListValue::GetList(size_t index, ListValue** out_value) { |
1220 return static_cast<const ListValue&>(*this).GetList( | 1227 return static_cast<const ListValue&>(*this).GetList( |
1221 index, | 1228 index, |
1222 const_cast<const ListValue**>(out_value)); | 1229 const_cast<const ListValue**>(out_value)); |
1223 } | 1230 } |
1224 | 1231 |
1225 bool ListValue::Remove(size_t index, std::unique_ptr<Value>* out_value) { | 1232 bool ListValue::Remove(size_t index, std::unique_ptr<Value>* out_value) { |
1226 if (index >= list_.size()) | 1233 if (index >= list_->size()) |
1227 return false; | 1234 return false; |
1228 | 1235 |
1229 if (out_value) | 1236 if (out_value) |
1230 *out_value = std::move(list_[index]); | 1237 *out_value = std::move((*list_)[index]); |
1231 | 1238 |
1232 list_.erase(list_.begin() + index); | 1239 list_->erase(list_->begin() + index); |
1233 return true; | 1240 return true; |
1234 } | 1241 } |
1235 | 1242 |
1236 bool ListValue::Remove(const Value& value, size_t* index) { | 1243 bool ListValue::Remove(const Value& value, size_t* index) { |
1237 for (auto it = list_.begin(); it != list_.end(); ++it) { | 1244 for (auto it = list_->begin(); it != list_->end(); ++it) { |
1238 if ((*it)->Equals(&value)) { | 1245 if ((*it)->Equals(&value)) { |
1239 size_t previous_index = it - list_.begin(); | 1246 size_t previous_index = it - list_->begin(); |
1240 list_.erase(it); | 1247 list_->erase(it); |
1241 | 1248 |
1242 if (index) | 1249 if (index) |
1243 *index = previous_index; | 1250 *index = previous_index; |
1244 return true; | 1251 return true; |
1245 } | 1252 } |
1246 } | 1253 } |
1247 return false; | 1254 return false; |
1248 } | 1255 } |
1249 | 1256 |
1250 ListValue::iterator ListValue::Erase(iterator iter, | 1257 ListValue::iterator ListValue::Erase(iterator iter, |
1251 std::unique_ptr<Value>* out_value) { | 1258 std::unique_ptr<Value>* out_value) { |
1252 if (out_value) | 1259 if (out_value) |
1253 *out_value = std::move(*Storage::iterator(iter)); | 1260 *out_value = std::move(*ListStorage::iterator(iter)); |
1254 | 1261 |
1255 return list_.erase(iter); | 1262 return list_->erase(iter); |
1256 } | 1263 } |
1257 | 1264 |
1258 void ListValue::Append(std::unique_ptr<Value> in_value) { | 1265 void ListValue::Append(std::unique_ptr<Value> in_value) { |
1259 list_.push_back(std::move(in_value)); | 1266 list_->push_back(std::move(in_value)); |
1260 } | 1267 } |
1261 | 1268 |
1262 #if !defined(OS_LINUX) | 1269 #if !defined(OS_LINUX) |
1263 void ListValue::Append(Value* in_value) { | 1270 void ListValue::Append(Value* in_value) { |
1264 DCHECK(in_value); | 1271 DCHECK(in_value); |
1265 Append(WrapUnique(in_value)); | 1272 Append(WrapUnique(in_value)); |
1266 } | 1273 } |
1267 #endif | 1274 #endif |
1268 | 1275 |
1269 void ListValue::AppendBoolean(bool in_value) { | 1276 void ListValue::AppendBoolean(bool in_value) { |
(...skipping 25 matching lines...) Expand all Loading... | |
1295 | 1302 |
1296 void ListValue::AppendStrings(const std::vector<string16>& in_values) { | 1303 void ListValue::AppendStrings(const std::vector<string16>& in_values) { |
1297 for (std::vector<string16>::const_iterator it = in_values.begin(); | 1304 for (std::vector<string16>::const_iterator it = in_values.begin(); |
1298 it != in_values.end(); ++it) { | 1305 it != in_values.end(); ++it) { |
1299 AppendString(*it); | 1306 AppendString(*it); |
1300 } | 1307 } |
1301 } | 1308 } |
1302 | 1309 |
1303 bool ListValue::AppendIfNotPresent(std::unique_ptr<Value> in_value) { | 1310 bool ListValue::AppendIfNotPresent(std::unique_ptr<Value> in_value) { |
1304 DCHECK(in_value); | 1311 DCHECK(in_value); |
1305 for (const auto& entry : list_) { | 1312 for (const auto& entry : *list_) { |
1306 if (entry->Equals(in_value.get())) { | 1313 if (entry->Equals(in_value.get())) { |
1307 return false; | 1314 return false; |
1308 } | 1315 } |
1309 } | 1316 } |
1310 list_.push_back(std::move(in_value)); | 1317 list_->push_back(std::move(in_value)); |
1311 return true; | 1318 return true; |
1312 } | 1319 } |
1313 | 1320 |
1314 bool ListValue::Insert(size_t index, std::unique_ptr<Value> in_value) { | 1321 bool ListValue::Insert(size_t index, std::unique_ptr<Value> in_value) { |
1315 DCHECK(in_value); | 1322 DCHECK(in_value); |
1316 if (index > list_.size()) | 1323 if (index > list_->size()) |
1317 return false; | 1324 return false; |
1318 | 1325 |
1319 list_.insert(list_.begin() + index, std::move(in_value)); | 1326 list_->insert(list_->begin() + index, std::move(in_value)); |
1320 return true; | 1327 return true; |
1321 } | 1328 } |
1322 | 1329 |
1323 ListValue::const_iterator ListValue::Find(const Value& value) const { | 1330 ListValue::const_iterator ListValue::Find(const Value& value) const { |
1324 return std::find_if(list_.begin(), list_.end(), | 1331 return std::find_if(list_->begin(), list_->end(), |
1325 [&value](const std::unique_ptr<Value>& entry) { | 1332 [&value](const std::unique_ptr<Value>& entry) { |
1326 return entry->Equals(&value); | 1333 return entry->Equals(&value); |
1327 }); | 1334 }); |
1328 } | 1335 } |
1329 | 1336 |
1330 void ListValue::Swap(ListValue* other) { | 1337 void ListValue::Swap(ListValue* other) { |
1331 list_.swap(other->list_); | 1338 list_->swap(*(other->list_)); |
1332 } | |
1333 | |
1334 bool ListValue::GetAsList(ListValue** out_value) { | |
1335 if (out_value) | |
1336 *out_value = this; | |
1337 return true; | |
1338 } | |
1339 | |
1340 bool ListValue::GetAsList(const ListValue** out_value) const { | |
1341 if (out_value) | |
1342 *out_value = this; | |
1343 return true; | |
1344 } | 1339 } |
1345 | 1340 |
1346 ListValue* ListValue::DeepCopy() const { | 1341 ListValue* ListValue::DeepCopy() const { |
1347 ListValue* result = new ListValue; | 1342 return static_cast<ListValue*>(Value::DeepCopy()); |
1348 | |
1349 for (const auto& entry : list_) | |
1350 result->Append(entry->CreateDeepCopy()); | |
1351 | |
1352 return result; | |
1353 } | 1343 } |
1354 | 1344 |
1355 std::unique_ptr<ListValue> ListValue::CreateDeepCopy() const { | 1345 std::unique_ptr<ListValue> ListValue::CreateDeepCopy() const { |
1356 return WrapUnique(DeepCopy()); | 1346 return WrapUnique(DeepCopy()); |
1357 } | 1347 } |
1358 | 1348 |
1359 bool ListValue::Equals(const Value* other) const { | |
1360 if (other->GetType() != GetType()) | |
1361 return false; | |
1362 | |
1363 const ListValue* other_list = | |
1364 static_cast<const ListValue*>(other); | |
1365 Storage::const_iterator lhs_it, rhs_it; | |
1366 for (lhs_it = begin(), rhs_it = other_list->begin(); | |
1367 lhs_it != end() && rhs_it != other_list->end(); | |
1368 ++lhs_it, ++rhs_it) { | |
1369 if (!(*lhs_it)->Equals(rhs_it->get())) | |
1370 return false; | |
1371 } | |
1372 if (lhs_it != end() || rhs_it != other_list->end()) | |
1373 return false; | |
1374 | |
1375 return true; | |
1376 } | |
1377 | |
1378 ValueSerializer::~ValueSerializer() { | 1349 ValueSerializer::~ValueSerializer() { |
1379 } | 1350 } |
1380 | 1351 |
1381 ValueDeserializer::~ValueDeserializer() { | 1352 ValueDeserializer::~ValueDeserializer() { |
1382 } | 1353 } |
1383 | 1354 |
1384 std::ostream& operator<<(std::ostream& out, const Value& value) { | 1355 std::ostream& operator<<(std::ostream& out, const Value& value) { |
1385 std::string json; | 1356 std::string json; |
1386 JSONWriter::WriteWithOptions(value, JSONWriter::OPTIONS_PRETTY_PRINT, &json); | 1357 JSONWriter::WriteWithOptions(value, JSONWriter::OPTIONS_PRETTY_PRINT, &json); |
1387 return out << json; | 1358 return out << json; |
1388 } | 1359 } |
1389 | 1360 |
1390 std::ostream& operator<<(std::ostream& out, const Value::Type& type) { | 1361 std::ostream& operator<<(std::ostream& out, const Value::Type& type) { |
1391 if (static_cast<int>(type) < 0 || | 1362 if (static_cast<int>(type) < 0 || |
1392 static_cast<size_t>(type) >= arraysize(kTypeNames)) | 1363 static_cast<size_t>(type) >= arraysize(kTypeNames)) |
1393 return out << "Invalid Type (index = " << static_cast<int>(type) << ")"; | 1364 return out << "Invalid Type (index = " << static_cast<int>(type) << ")"; |
1394 return out << Value::GetTypeName(type); | 1365 return out << Value::GetTypeName(type); |
1395 } | 1366 } |
1396 | 1367 |
1397 } // namespace base | 1368 } // namespace base |
OLD | NEW |