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 #ifndef BASE_JSON_JSON_VALUE_CONVERTER_H_ | 5 #ifndef BASE_JSON_JSON_VALUE_CONVERTER_H_ |
6 #define BASE_JSON_JSON_VALUE_CONVERTER_H_ | 6 #define BASE_JSON_JSON_VALUE_CONVERTER_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 | 9 |
10 #include <memory> | 10 #include <memory> |
11 #include <string> | 11 #include <string> |
12 #include <vector> | 12 #include <vector> |
13 | 13 |
14 #include "base/base_export.h" | 14 #include "base/base_export.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/macros.h" | 16 #include "base/macros.h" |
17 #include "base/memory/scoped_vector.h" | 17 #include "base/memory/ptr_util.h" |
18 #include "base/strings/string16.h" | 18 #include "base/strings/string16.h" |
19 #include "base/strings/string_piece.h" | 19 #include "base/strings/string_piece.h" |
20 #include "base/values.h" | 20 #include "base/values.h" |
21 | 21 |
22 // JSONValueConverter converts a JSON value into a C++ struct in a | 22 // JSONValueConverter converts a JSON value into a C++ struct in a |
23 // lightweight way. | 23 // lightweight way. |
24 // | 24 // |
25 // Usage: | 25 // Usage: |
26 // For real examples, you may want to refer to _unittest.cc file. | 26 // For real examples, you may want to refer to _unittest.cc file. |
27 // | 27 // |
(...skipping 30 matching lines...) Expand all Loading... |
58 // method. Then, just use RegisterNestedField() from the containing struct's | 58 // method. Then, just use RegisterNestedField() from the containing struct's |
59 // RegisterJSONConverter method. | 59 // RegisterJSONConverter method. |
60 // struct Nested { | 60 // struct Nested { |
61 // Message foo; | 61 // Message foo; |
62 // static void RegisterJSONConverter(...) { | 62 // static void RegisterJSONConverter(...) { |
63 // ... | 63 // ... |
64 // converter->RegisterNestedField("foo", &Nested::foo); | 64 // converter->RegisterNestedField("foo", &Nested::foo); |
65 // } | 65 // } |
66 // }; | 66 // }; |
67 // | 67 // |
68 // For repeated field, we just assume ScopedVector for its container | 68 // For repeated field, we just assume std::vector<std::unique_ptr<ElementType>> |
69 // and you can put RegisterRepeatedInt or some other types. Use | 69 // for its container and you can put RegisterRepeatedInt or some other types. |
70 // RegisterRepeatedMessage for nested repeated fields. | 70 // Use RegisterRepeatedMessage for nested repeated fields. |
71 // | 71 // |
72 // Sometimes JSON format uses string representations for other types such | 72 // Sometimes JSON format uses string representations for other types such |
73 // like enum, timestamp, or URL. You can use RegisterCustomField method | 73 // like enum, timestamp, or URL. You can use RegisterCustomField method |
74 // and specify a function to convert a StringPiece to your type. | 74 // and specify a function to convert a StringPiece to your type. |
75 // bool ConvertFunc(const StringPiece& s, YourEnum* result) { | 75 // bool ConvertFunc(const StringPiece& s, YourEnum* result) { |
76 // // do something and return true if succeed... | 76 // // do something and return true if succeed... |
77 // } | 77 // } |
78 // struct Message { | 78 // struct Message { |
79 // YourEnum ye; | 79 // YourEnum ye; |
80 // ... | 80 // ... |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 bool Convert(const base::Value& value, NestedType* field) const override { | 240 bool Convert(const base::Value& value, NestedType* field) const override { |
241 return converter_.Convert(value, field); | 241 return converter_.Convert(value, field); |
242 } | 242 } |
243 | 243 |
244 private: | 244 private: |
245 JSONValueConverter<NestedType> converter_; | 245 JSONValueConverter<NestedType> converter_; |
246 DISALLOW_COPY_AND_ASSIGN(NestedValueConverter); | 246 DISALLOW_COPY_AND_ASSIGN(NestedValueConverter); |
247 }; | 247 }; |
248 | 248 |
249 template <typename Element> | 249 template <typename Element> |
250 class RepeatedValueConverter : public ValueConverter<ScopedVector<Element> > { | 250 class RepeatedValueConverter |
| 251 : public ValueConverter<std::vector<std::unique_ptr<Element>>> { |
251 public: | 252 public: |
252 RepeatedValueConverter() {} | 253 RepeatedValueConverter() {} |
253 | 254 |
254 bool Convert(const base::Value& value, | 255 bool Convert(const base::Value& value, |
255 ScopedVector<Element>* field) const override { | 256 std::vector<std::unique_ptr<Element>>* field) const override { |
256 const base::ListValue* list = NULL; | 257 const base::ListValue* list = NULL; |
257 if (!value.GetAsList(&list)) { | 258 if (!value.GetAsList(&list)) { |
258 // The field is not a list. | 259 // The field is not a list. |
259 return false; | 260 return false; |
260 } | 261 } |
261 | 262 |
262 field->reserve(list->GetSize()); | 263 field->reserve(list->GetSize()); |
263 for (size_t i = 0; i < list->GetSize(); ++i) { | 264 for (size_t i = 0; i < list->GetSize(); ++i) { |
264 const base::Value* element = NULL; | 265 const base::Value* element = NULL; |
265 if (!list->Get(i, &element)) | 266 if (!list->Get(i, &element)) |
266 continue; | 267 continue; |
267 | 268 |
268 std::unique_ptr<Element> e(new Element); | 269 std::unique_ptr<Element> e(new Element); |
269 if (basic_converter_.Convert(*element, e.get())) { | 270 if (basic_converter_.Convert(*element, e.get())) { |
270 field->push_back(e.release()); | 271 field->push_back(std::move(e)); |
271 } else { | 272 } else { |
272 DVLOG(1) << "failure at " << i << "-th element"; | 273 DVLOG(1) << "failure at " << i << "-th element"; |
273 return false; | 274 return false; |
274 } | 275 } |
275 } | 276 } |
276 return true; | 277 return true; |
277 } | 278 } |
278 | 279 |
279 private: | 280 private: |
280 BasicValueConverter<Element> basic_converter_; | 281 BasicValueConverter<Element> basic_converter_; |
281 DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter); | 282 DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter); |
282 }; | 283 }; |
283 | 284 |
284 template <typename NestedType> | 285 template <typename NestedType> |
285 class RepeatedMessageConverter | 286 class RepeatedMessageConverter |
286 : public ValueConverter<ScopedVector<NestedType> > { | 287 : public ValueConverter<std::vector<std::unique_ptr<NestedType>>> { |
287 public: | 288 public: |
288 RepeatedMessageConverter() {} | 289 RepeatedMessageConverter() {} |
289 | 290 |
290 bool Convert(const base::Value& value, | 291 bool Convert(const base::Value& value, |
291 ScopedVector<NestedType>* field) const override { | 292 std::vector<std::unique_ptr<NestedType>>* field) const override { |
292 const base::ListValue* list = NULL; | 293 const base::ListValue* list = NULL; |
293 if (!value.GetAsList(&list)) | 294 if (!value.GetAsList(&list)) |
294 return false; | 295 return false; |
295 | 296 |
296 field->reserve(list->GetSize()); | 297 field->reserve(list->GetSize()); |
297 for (size_t i = 0; i < list->GetSize(); ++i) { | 298 for (size_t i = 0; i < list->GetSize(); ++i) { |
298 const base::Value* element = NULL; | 299 const base::Value* element = NULL; |
299 if (!list->Get(i, &element)) | 300 if (!list->Get(i, &element)) |
300 continue; | 301 continue; |
301 | 302 |
302 std::unique_ptr<NestedType> nested(new NestedType); | 303 std::unique_ptr<NestedType> nested(new NestedType); |
303 if (converter_.Convert(*element, nested.get())) { | 304 if (converter_.Convert(*element, nested.get())) { |
304 field->push_back(nested.release()); | 305 field->push_back(std::move(nested)); |
305 } else { | 306 } else { |
306 DVLOG(1) << "failure at " << i << "-th element"; | 307 DVLOG(1) << "failure at " << i << "-th element"; |
307 return false; | 308 return false; |
308 } | 309 } |
309 } | 310 } |
310 return true; | 311 return true; |
311 } | 312 } |
312 | 313 |
313 private: | 314 private: |
314 JSONValueConverter<NestedType> converter_; | 315 JSONValueConverter<NestedType> converter_; |
315 DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter); | 316 DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter); |
316 }; | 317 }; |
317 | 318 |
318 template <typename NestedType> | 319 template <typename NestedType> |
319 class RepeatedCustomValueConverter | 320 class RepeatedCustomValueConverter |
320 : public ValueConverter<ScopedVector<NestedType> > { | 321 : public ValueConverter<std::vector<std::unique_ptr<NestedType>>> { |
321 public: | 322 public: |
322 typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field); | 323 typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field); |
323 | 324 |
324 explicit RepeatedCustomValueConverter(ConvertFunc convert_func) | 325 explicit RepeatedCustomValueConverter(ConvertFunc convert_func) |
325 : convert_func_(convert_func) {} | 326 : convert_func_(convert_func) {} |
326 | 327 |
327 bool Convert(const base::Value& value, | 328 bool Convert(const base::Value& value, |
328 ScopedVector<NestedType>* field) const override { | 329 std::vector<std::unique_ptr<NestedType>>* field) const override { |
329 const base::ListValue* list = NULL; | 330 const base::ListValue* list = NULL; |
330 if (!value.GetAsList(&list)) | 331 if (!value.GetAsList(&list)) |
331 return false; | 332 return false; |
332 | 333 |
333 field->reserve(list->GetSize()); | 334 field->reserve(list->GetSize()); |
334 for (size_t i = 0; i < list->GetSize(); ++i) { | 335 for (size_t i = 0; i < list->GetSize(); ++i) { |
335 const base::Value* element = NULL; | 336 const base::Value* element = NULL; |
336 if (!list->Get(i, &element)) | 337 if (!list->Get(i, &element)) |
337 continue; | 338 continue; |
338 | 339 |
339 std::unique_ptr<NestedType> nested(new NestedType); | 340 std::unique_ptr<NestedType> nested(new NestedType); |
340 if ((*convert_func_)(element, nested.get())) { | 341 if ((*convert_func_)(element, nested.get())) { |
341 field->push_back(nested.release()); | 342 field->push_back(std::move(nested)); |
342 } else { | 343 } else { |
343 DVLOG(1) << "failure at " << i << "-th element"; | 344 DVLOG(1) << "failure at " << i << "-th element"; |
344 return false; | 345 return false; |
345 } | 346 } |
346 } | 347 } |
347 return true; | 348 return true; |
348 } | 349 } |
349 | 350 |
350 private: | 351 private: |
351 ConvertFunc convert_func_; | 352 ConvertFunc convert_func_; |
352 DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter); | 353 DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter); |
353 }; | 354 }; |
354 | 355 |
355 | 356 |
356 } // namespace internal | 357 } // namespace internal |
357 | 358 |
358 template <class StructType> | 359 template <class StructType> |
359 class JSONValueConverter { | 360 class JSONValueConverter { |
360 public: | 361 public: |
361 JSONValueConverter() { | 362 JSONValueConverter() { |
362 StructType::RegisterJSONConverter(this); | 363 StructType::RegisterJSONConverter(this); |
363 } | 364 } |
364 | 365 |
365 void RegisterIntField(const std::string& field_name, | 366 void RegisterIntField(const std::string& field_name, |
366 int StructType::* field) { | 367 int StructType::* field) { |
367 fields_.push_back(new internal::FieldConverter<StructType, int>( | 368 fields_.push_back(MakeUnique<internal::FieldConverter<StructType, int>>( |
368 field_name, field, new internal::BasicValueConverter<int>)); | 369 field_name, field, new internal::BasicValueConverter<int>)); |
369 } | 370 } |
370 | 371 |
371 void RegisterStringField(const std::string& field_name, | 372 void RegisterStringField(const std::string& field_name, |
372 std::string StructType::* field) { | 373 std::string StructType::* field) { |
373 fields_.push_back(new internal::FieldConverter<StructType, std::string>( | 374 fields_.push_back( |
374 field_name, field, new internal::BasicValueConverter<std::string>)); | 375 MakeUnique<internal::FieldConverter<StructType, std::string>>( |
| 376 field_name, field, new internal::BasicValueConverter<std::string>)); |
375 } | 377 } |
376 | 378 |
377 void RegisterStringField(const std::string& field_name, | 379 void RegisterStringField(const std::string& field_name, |
378 string16 StructType::* field) { | 380 string16 StructType::* field) { |
379 fields_.push_back(new internal::FieldConverter<StructType, string16>( | 381 fields_.push_back( |
380 field_name, field, new internal::BasicValueConverter<string16>)); | 382 MakeUnique<internal::FieldConverter<StructType, string16>>( |
| 383 field_name, field, new internal::BasicValueConverter<string16>)); |
381 } | 384 } |
382 | 385 |
383 void RegisterBoolField(const std::string& field_name, | 386 void RegisterBoolField(const std::string& field_name, |
384 bool StructType::* field) { | 387 bool StructType::* field) { |
385 fields_.push_back(new internal::FieldConverter<StructType, bool>( | 388 fields_.push_back(MakeUnique<internal::FieldConverter<StructType, bool>>( |
386 field_name, field, new internal::BasicValueConverter<bool>)); | 389 field_name, field, new internal::BasicValueConverter<bool>)); |
387 } | 390 } |
388 | 391 |
389 void RegisterDoubleField(const std::string& field_name, | 392 void RegisterDoubleField(const std::string& field_name, |
390 double StructType::* field) { | 393 double StructType::* field) { |
391 fields_.push_back(new internal::FieldConverter<StructType, double>( | 394 fields_.push_back(MakeUnique<internal::FieldConverter<StructType, double>>( |
392 field_name, field, new internal::BasicValueConverter<double>)); | 395 field_name, field, new internal::BasicValueConverter<double>)); |
393 } | 396 } |
394 | 397 |
395 template <class NestedType> | 398 template <class NestedType> |
396 void RegisterNestedField( | 399 void RegisterNestedField( |
397 const std::string& field_name, NestedType StructType::* field) { | 400 const std::string& field_name, NestedType StructType::* field) { |
398 fields_.push_back(new internal::FieldConverter<StructType, NestedType>( | 401 fields_.push_back( |
399 field_name, | 402 MakeUnique<internal::FieldConverter<StructType, NestedType>>( |
400 field, | 403 field_name, field, new internal::NestedValueConverter<NestedType>)); |
401 new internal::NestedValueConverter<NestedType>)); | |
402 } | 404 } |
403 | 405 |
404 template <typename FieldType> | 406 template <typename FieldType> |
405 void RegisterCustomField( | 407 void RegisterCustomField( |
406 const std::string& field_name, | 408 const std::string& field_name, |
407 FieldType StructType::* field, | 409 FieldType StructType::* field, |
408 bool (*convert_func)(const StringPiece&, FieldType*)) { | 410 bool (*convert_func)(const StringPiece&, FieldType*)) { |
409 fields_.push_back(new internal::FieldConverter<StructType, FieldType>( | 411 fields_.push_back( |
410 field_name, | 412 MakeUnique<internal::FieldConverter<StructType, FieldType>>( |
411 field, | 413 field_name, field, |
412 new internal::CustomFieldConverter<FieldType>(convert_func))); | 414 new internal::CustomFieldConverter<FieldType>(convert_func))); |
413 } | 415 } |
414 | 416 |
415 template <typename FieldType> | 417 template <typename FieldType> |
416 void RegisterCustomValueField( | 418 void RegisterCustomValueField( |
417 const std::string& field_name, | 419 const std::string& field_name, |
418 FieldType StructType::* field, | 420 FieldType StructType::* field, |
419 bool (*convert_func)(const base::Value*, FieldType*)) { | 421 bool (*convert_func)(const base::Value*, FieldType*)) { |
420 fields_.push_back(new internal::FieldConverter<StructType, FieldType>( | 422 fields_.push_back( |
421 field_name, | 423 MakeUnique<internal::FieldConverter<StructType, FieldType>>( |
422 field, | 424 field_name, field, |
423 new internal::ValueFieldConverter<FieldType>(convert_func))); | 425 new internal::ValueFieldConverter<FieldType>(convert_func))); |
424 } | 426 } |
425 | 427 |
426 void RegisterRepeatedInt(const std::string& field_name, | 428 void RegisterRepeatedInt( |
427 ScopedVector<int> StructType::* field) { | 429 const std::string& field_name, |
| 430 std::vector<std::unique_ptr<int>> StructType::*field) { |
428 fields_.push_back( | 431 fields_.push_back( |
429 new internal::FieldConverter<StructType, ScopedVector<int> >( | 432 MakeUnique<internal::FieldConverter<StructType, |
| 433 std::vector<std::unique_ptr<int>>>>( |
430 field_name, field, new internal::RepeatedValueConverter<int>)); | 434 field_name, field, new internal::RepeatedValueConverter<int>)); |
431 } | 435 } |
432 | 436 |
433 void RegisterRepeatedString(const std::string& field_name, | 437 void RegisterRepeatedString( |
434 ScopedVector<std::string> StructType::* field) { | 438 const std::string& field_name, |
| 439 std::vector<std::unique_ptr<std::string>> StructType::*field) { |
435 fields_.push_back( | 440 fields_.push_back( |
436 new internal::FieldConverter<StructType, ScopedVector<std::string> >( | 441 MakeUnique<internal::FieldConverter< |
437 field_name, | 442 StructType, std::vector<std::unique_ptr<std::string>>>>( |
438 field, | 443 field_name, field, |
439 new internal::RepeatedValueConverter<std::string>)); | 444 new internal::RepeatedValueConverter<std::string>)); |
440 } | 445 } |
441 | 446 |
442 void RegisterRepeatedString(const std::string& field_name, | 447 void RegisterRepeatedString( |
443 ScopedVector<string16> StructType::* field) { | 448 const std::string& field_name, |
444 fields_.push_back( | 449 std::vector<std::unique_ptr<string16>> StructType::*field) { |
445 new internal::FieldConverter<StructType, ScopedVector<string16> >( | 450 fields_.push_back(MakeUnique<internal::FieldConverter< |
446 field_name, | 451 StructType, std::vector<std::unique_ptr<string16>>>>( |
447 field, | 452 field_name, field, new internal::RepeatedValueConverter<string16>)); |
448 new internal::RepeatedValueConverter<string16>)); | |
449 } | 453 } |
450 | 454 |
451 void RegisterRepeatedDouble(const std::string& field_name, | 455 void RegisterRepeatedDouble( |
452 ScopedVector<double> StructType::* field) { | 456 const std::string& field_name, |
453 fields_.push_back( | 457 std::vector<std::unique_ptr<double>> StructType::*field) { |
454 new internal::FieldConverter<StructType, ScopedVector<double> >( | 458 fields_.push_back(MakeUnique<internal::FieldConverter< |
455 field_name, field, new internal::RepeatedValueConverter<double>)); | 459 StructType, std::vector<std::unique_ptr<double>>>>( |
| 460 field_name, field, new internal::RepeatedValueConverter<double>)); |
456 } | 461 } |
457 | 462 |
458 void RegisterRepeatedBool(const std::string& field_name, | 463 void RegisterRepeatedBool( |
459 ScopedVector<bool> StructType::* field) { | 464 const std::string& field_name, |
460 fields_.push_back( | 465 std::vector<std::unique_ptr<bool>> StructType::*field) { |
461 new internal::FieldConverter<StructType, ScopedVector<bool> >( | 466 fields_.push_back(MakeUnique<internal::FieldConverter< |
462 field_name, field, new internal::RepeatedValueConverter<bool>)); | 467 StructType, std::vector<std::unique_ptr<bool>>>>( |
| 468 field_name, field, new internal::RepeatedValueConverter<bool>)); |
463 } | 469 } |
464 | 470 |
465 template <class NestedType> | 471 template <class NestedType> |
466 void RegisterRepeatedCustomValue( | 472 void RegisterRepeatedCustomValue( |
467 const std::string& field_name, | 473 const std::string& field_name, |
468 ScopedVector<NestedType> StructType::* field, | 474 std::vector<std::unique_ptr<NestedType>> StructType::*field, |
469 bool (*convert_func)(const base::Value*, NestedType*)) { | 475 bool (*convert_func)(const base::Value*, NestedType*)) { |
470 fields_.push_back( | 476 fields_.push_back( |
471 new internal::FieldConverter<StructType, ScopedVector<NestedType> >( | 477 MakeUnique<internal::FieldConverter< |
472 field_name, | 478 StructType, std::vector<std::unique_ptr<NestedType>>>>( |
473 field, | 479 field_name, field, |
474 new internal::RepeatedCustomValueConverter<NestedType>( | 480 new internal::RepeatedCustomValueConverter<NestedType>( |
475 convert_func))); | 481 convert_func))); |
476 } | 482 } |
477 | 483 |
478 template <class NestedType> | 484 template <class NestedType> |
479 void RegisterRepeatedMessage(const std::string& field_name, | 485 void RegisterRepeatedMessage( |
480 ScopedVector<NestedType> StructType::* field) { | 486 const std::string& field_name, |
| 487 std::vector<std::unique_ptr<NestedType>> StructType::*field) { |
481 fields_.push_back( | 488 fields_.push_back( |
482 new internal::FieldConverter<StructType, ScopedVector<NestedType> >( | 489 MakeUnique<internal::FieldConverter< |
483 field_name, | 490 StructType, std::vector<std::unique_ptr<NestedType>>>>( |
484 field, | 491 field_name, field, |
485 new internal::RepeatedMessageConverter<NestedType>)); | 492 new internal::RepeatedMessageConverter<NestedType>)); |
486 } | 493 } |
487 | 494 |
488 bool Convert(const base::Value& value, StructType* output) const { | 495 bool Convert(const base::Value& value, StructType* output) const { |
489 const DictionaryValue* dictionary_value = NULL; | 496 const DictionaryValue* dictionary_value = NULL; |
490 if (!value.GetAsDictionary(&dictionary_value)) | 497 if (!value.GetAsDictionary(&dictionary_value)) |
491 return false; | 498 return false; |
492 | 499 |
493 for (size_t i = 0; i < fields_.size(); ++i) { | 500 for (size_t i = 0; i < fields_.size(); ++i) { |
494 const internal::FieldConverterBase<StructType>* field_converter = | 501 const internal::FieldConverterBase<StructType>* field_converter = |
495 fields_[i]; | 502 fields_[i].get(); |
496 const base::Value* field = NULL; | 503 const base::Value* field = NULL; |
497 if (dictionary_value->Get(field_converter->field_path(), &field)) { | 504 if (dictionary_value->Get(field_converter->field_path(), &field)) { |
498 if (!field_converter->ConvertField(*field, output)) { | 505 if (!field_converter->ConvertField(*field, output)) { |
499 DVLOG(1) << "failure at field " << field_converter->field_path(); | 506 DVLOG(1) << "failure at field " << field_converter->field_path(); |
500 return false; | 507 return false; |
501 } | 508 } |
502 } | 509 } |
503 } | 510 } |
504 return true; | 511 return true; |
505 } | 512 } |
506 | 513 |
507 private: | 514 private: |
508 ScopedVector<internal::FieldConverterBase<StructType> > fields_; | 515 std::vector<std::unique_ptr<internal::FieldConverterBase<StructType>>> |
| 516 fields_; |
509 | 517 |
510 DISALLOW_COPY_AND_ASSIGN(JSONValueConverter); | 518 DISALLOW_COPY_AND_ASSIGN(JSONValueConverter); |
511 }; | 519 }; |
512 | 520 |
513 } // namespace base | 521 } // namespace base |
514 | 522 |
515 #endif // BASE_JSON_JSON_VALUE_CONVERTER_H_ | 523 #endif // BASE_JSON_JSON_VALUE_CONVERTER_H_ |
OLD | NEW |