Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(438)

Side by Side Diff: sdk/lib/collection/iterable.dart

Issue 297053002: Reinstall previous behavior for Set and Queue toString. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Retain a typo fix. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.collection; 5 part of dart.collection;
6 6
7 /** 7 /**
8 * This [Iterable] mixin implements all [Iterable] members except `iterator`. 8 * This [Iterable] mixin implements all [Iterable] members except `iterator`.
9 * 9 *
10 * All other methods are implemented in terms of `iterator`. 10 * All other methods are implemented in terms of `iterator`.
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 E elementAt(int index) { 188 E elementAt(int index) {
189 if (index is! int || index < 0) throw new RangeError.value(index); 189 if (index is! int || index < 0) throw new RangeError.value(index);
190 int remaining = index; 190 int remaining = index;
191 for (E element in this) { 191 for (E element in this) {
192 if (remaining == 0) return element; 192 if (remaining == 0) return element;
193 remaining--; 193 remaining--;
194 } 194 }
195 throw new RangeError.value(index); 195 throw new RangeError.value(index);
196 } 196 }
197 197
198 String toString() => _iterableToString(this); 198 String toString() => IterableBase.iterableToShortString(this, '(', ')');
199 } 199 }
200 200
201 /** 201 /**
202 * Base class for implementing [Iterable]. 202 * Base class for implementing [Iterable].
203 * 203 *
204 * This class implements all methods of [Iterable] except [Iterable.iterator] 204 * This class implements all methods of [Iterable] except [Iterable.iterator]
205 * in terms of `iterator`. 205 * in terms of `iterator`.
206 */ 206 */
207 abstract class IterableBase<E> implements Iterable<E> { 207 abstract class IterableBase<E> implements Iterable<E> {
208 // TODO(lrn): Base this on IterableMixin if there ever becomes a way 208 // TODO(lrn): Base this on IterableMixin if there ever becomes a way
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 * Elements are represented by their own `toString` results. 395 * Elements are represented by their own `toString` results.
396 * 396 *
397 * The representation always contains the first three elements. 397 * The representation always contains the first three elements.
398 * If there are less than a hundred elements in the iterable, it also 398 * If there are less than a hundred elements in the iterable, it also
399 * contains the last two elements. 399 * contains the last two elements.
400 * 400 *
401 * If the resulting string isn't above 80 characters, more elements are 401 * If the resulting string isn't above 80 characters, more elements are
402 * included from the start of the iterable. 402 * included from the start of the iterable.
403 * 403 *
404 * The conversion may omit calling `toString` on some elements if they 404 * The conversion may omit calling `toString` on some elements if they
405 * are known to now occur in the output, and it may stop iterating after 405 * are known to not occur in the output, and it may stop iterating after
406 * a hundred elements. 406 * a hundred elements.
407 */ 407 */
408 String toString() => _iterableToString(this); 408 String toString() => IterableBase.iterableToShortString(this, '(', ')');
floitsch 2014/05/23 16:09:58 -IterableBase.-
Lasse Reichstein Nielsen 2014/05/23 16:50:01 You mean I should remove it? It is in the same cla
409 }
410 409
411 String _setToString(Set set) => _collectionToString(set, "{" , "}"); 410 /**
412 411 * Convert an `Iterable` to a string like [IterableBase.toString].
413 String _iterableToString(Iterable iterable) => 412 *
414 _collectionToString(iterable, "(", ")"); 413 * Allows using other delimiters than '(' and ')'.
415 414 *
416 String _collectionToString(Iterable iterable, String before, String after) { 415 * Handles circular references where converting one of the elements
417 if (_toStringVisiting.contains(iterable)) return "$before...$after"; 416 * to a string ends up converting [iterable] to a string again.
418 _toStringVisiting.add(iterable); 417 */
419 List parts = []; 418 static String iterableToShortString(Iterable iterable,
floitsch 2014/05/23 16:09:58 Isn't this an exposed class? Do you want to expose
Lasse Reichstein Nielsen 2014/05/23 16:50:01 Yes, I want to expose it. I see no reason to have
420 try { 419 [String leftDelimiter = '(',
421 _collectionPartsToStrings(iterable, parts); 420 String rightDelimiter = ')']) {
422 } finally { 421 if (_toStringVisiting.contains(iterable)) {
423 _toStringVisiting.remove(iterable); 422 if (leftDelimiter == "(" && rightDelimiter == ")") {
424 } 423 // Avoid creating a new string in the "common" case.
425 return (new StringBuffer(before) 424 return "(...)";
426 ..writeAll(parts, ", ") 425 }
427 ..write(after)).toString(); 426 return "$leftDelimiter...$rightDelimiter";
428 }
429
430 /** Convert elments of [iterable] to strings and store them in [parts]. */
431 void _collectionPartsToStrings(Iterable iterable, List parts) {
432 /// Try to stay below this many characters.
433 const int LENGTH_LIMIT = 80;
434 /// Always at least this many elements at the start.
435 const int HEAD_COUNT = 3;
436 /// Always at least this many elements at the end.
437 const int TAIL_COUNT = 2;
438 /// Stop iterating after this many elements. Iterables can be infinite.
439 const int MAX_COUNT = 100;
440 // Per entry length overhead. It's for ", " for all after the first entry,
441 // and for "(" and ")" for the initial entry. By pure luck, that's the same
442 // number.
443 const int OVERHEAD = 2;
444 const int ELLIPSIS_SIZE = 3; // "...".length.
445 int length = 0;
446 int count = 0;
447 Iterator it = iterable.iterator;
448 // Initial run of elements, at least HEAD_COUNT, and then continue until
449 // passing at most LENGTH_LIMIT characters.
450 while (length < LENGTH_LIMIT || count < HEAD_COUNT) {
451 if (!it.moveNext()) {
452 return;
453 } 427 }
454 String next = "${it.current}"; 428 List parts = [];
455 parts.add(next); 429 _toStringVisiting.add(iterable);
456 length += next.length + OVERHEAD; 430 try {
457 count++; 431 _iterablePartsToStrings(iterable, parts);
432 } finally {
433 _toStringVisiting.remove(iterable);
434 }
435 return (new StringBuffer(leftDelimiter)
436 ..writeAll(parts, ", ")
437 ..write(rightDelimiter)).toString();
458 } 438 }
459 439
460 String penultimateString; 440 /**
461 String ultimateString; 441 * Converts an `Iterable` to a string.
442 *
443 * Converts each elements to a string, and separates the results by ", ".
444 * Then wraps the result in [leftDelimiter] and [rightDelimiter].
445 *
446 * Unlike [iterableToShortString], this conversion doesn't omit any
447 * elements or puts any limit on the size of the result.
448 *
449 * Handles circular references where converting one of the elements
450 * to a string ends up converting [iterable] to a string again.
451 */
452 static String iterableToFullString(Iterable iterable,
floitsch 2014/05/23 16:09:58 ditto.
Lasse Reichstein Nielsen 2014/05/23 16:50:01 And yes, intended public. I don't want anybody to
453 [String leftDelimiter = '(',
454 String rightDelimiter = ')']) {
455 if (_toStringVisiting.contains(iterable)) {
456 return "$leftDelimiter...$rightDelimiter";
457 }
458 StringBuffer buffer = new StringBuffer(leftDelimiter);
459 _toStringVisiting.add(iterable);
460 try {
461 buffer.writeAll(iterable, ", ");
462 } finally {
463 _toStringVisiting.remove(iterable);
464 }
465 buffer.write(rightDelimiter);
466 return buffer.toString();
467 }
462 468
463 // Find last two elements. One or more of them may already be in the 469 /** A set used to identify cyclic lists during toString() calls. */
464 // parts array. Include their length in `length`. 470 static Set _toStringVisiting = new HashSet.identity();
465 var penultimate = null; 471
466 var ultimate = null; 472 /**
467 if (!it.moveNext()) { 473 * Convert elments of [iterable] to strings and store them in [parts].
468 if (count <= HEAD_COUNT + TAIL_COUNT) return; 474 *
469 ultimateString = parts.removeLast(); 475 * This is the complicated part of [iterableToShortString].
470 penultimateString = parts.removeLast(); 476 * It is extracted as a separate function to avoid having too much code
471 } else { 477 * inside the try/finally.
floitsch 2014/05/23 16:09:58 This should not be a dart-doc comment. Feel free
Lasse Reichstein Nielsen 2014/05/23 16:50:01 Why not. It's a private method, so it won't be exp
472 penultimate = it.current; 478 */
473 count++; 479 static void _iterablePartsToStrings(Iterable iterable, List parts) {
480 /// Try to stay below this many characters.
481 const int LENGTH_LIMIT = 80;
482 /// Always at least this many elements at the start.
483 const int HEAD_COUNT = 3;
484 /// Always at least this many elements at the end.
485 const int TAIL_COUNT = 2;
486 /// Stop iterating after this many elements. Iterables can be infinite.
487 const int MAX_COUNT = 100;
488 // Per entry length overhead. It's for ", " for all after the first entry,
489 // and for "(" and ")" for the initial entry. By pure luck, that's the same
490 // number.
491 const int OVERHEAD = 2;
492 const int ELLIPSIS_SIZE = 3; // "...".length.
493
494 int length = 0;
495 int count = 0;
496 Iterator it = iterable.iterator;
497 // Initial run of elements, at least HEAD_COUNT, and then continue until
498 // passing at most LENGTH_LIMIT characters.
499 while (length < LENGTH_LIMIT || count < HEAD_COUNT) {
500 if (!it.moveNext()) return;
501 String next = "${it.current}";
502 parts.add(next);
503 length += next.length + OVERHEAD;
504 count++;
505 }
506
507 String penultimateString;
508 String ultimateString;
509
510 // Find last two elements. One or more of them may already be in the
511 // parts array. Include their length in `length`.
512 var penultimate = null;
513 var ultimate = null;
474 if (!it.moveNext()) { 514 if (!it.moveNext()) {
475 if (count <= HEAD_COUNT + 1) { 515 if (count <= HEAD_COUNT + TAIL_COUNT) return;
476 parts.add("$penultimate"); 516 ultimateString = parts.removeLast();
477 return;
478 }
479 ultimateString = "$penultimate";
480 penultimateString = parts.removeLast(); 517 penultimateString = parts.removeLast();
481 length += ultimateString.length + OVERHEAD;
482 } else { 518 } else {
483 ultimate = it.current; 519 penultimate = it.current;
484 count++; 520 count++;
485 // Then keep looping, keeping the last two elements in variables. 521 if (!it.moveNext()) {
486 assert(count < MAX_COUNT); 522 if (count <= HEAD_COUNT + 1) {
487 while (it.moveNext()) { 523 parts.add("$penultimate");
488 penultimate = ultimate; 524 return;
525 }
526 ultimateString = "$penultimate";
527 penultimateString = parts.removeLast();
528 length += ultimateString.length + OVERHEAD;
529 } else {
489 ultimate = it.current; 530 ultimate = it.current;
490 count++; 531 count++;
491 if (count > MAX_COUNT) { 532 // Then keep looping, keeping the last two elements in variables.
492 // If we haven't found the end before MAX_COUNT, give up. 533 assert(count < MAX_COUNT);
493 // This cannot happen in the code above because each entry 534 while (it.moveNext()) {
494 // increases length by at least two, so there is no way to 535 penultimate = ultimate;
495 // visit more than ~40 elements before this loop. 536 ultimate = it.current;
537 count++;
538 if (count > MAX_COUNT) {
539 // If we haven't found the end before MAX_COUNT, give up.
540 // This cannot happen in the code above because each entry
541 // increases length by at least two, so there is no way to
542 // visit more than ~40 elements before this loop.
496 543
497 // Remove any surplus elements until length, including ", ...)", 544 // Remove any surplus elements until length, including ", ...)",
498 // is at most LENGTH_LIMIT. 545 // is at most LENGTH_LIMIT.
499 while (length > LENGTH_LIMIT - ELLIPSIS_SIZE - OVERHEAD && 546 while (length > LENGTH_LIMIT - ELLIPSIS_SIZE - OVERHEAD &&
500 count > HEAD_COUNT) { 547 count > HEAD_COUNT) {
501 length -= parts.removeLast().length + OVERHEAD; 548 length -= parts.removeLast().length + OVERHEAD;
502 count--; 549 count--;
550 }
551 parts.add("...");
552 return;
503 } 553 }
504 parts.add("...");
505 return;
506 } 554 }
555 penultimateString = "$penultimate";
556 ultimateString = "$ultimate";
557 length +=
558 ultimateString.length + penultimateString.length + 2 * OVERHEAD;
507 } 559 }
508 penultimateString = "$penultimate";
509 ultimateString = "$ultimate";
510 length +=
511 ultimateString.length + penultimateString.length + 2 * OVERHEAD;
512 } 560 }
513 }
514 561
515 // If there is a gap between the initial run and the last two, 562 // If there is a gap between the initial run and the last two,
516 // prepare to add an ellipsis. 563 // prepare to add an ellipsis.
517 String elision = null; 564 String elision = null;
518 if (count > parts.length + TAIL_COUNT) { 565 if (count > parts.length + TAIL_COUNT) {
519 elision = "...";
520 length += ELLIPSIS_SIZE + OVERHEAD;
521 }
522
523 // If the last two elements were very long, and we have more than
524 // HEAD_COUNT elements in the initial run, drop some to make room for
525 // the last two.
526 while (length > LENGTH_LIMIT && parts.length > HEAD_COUNT) {
527 String lastPart = parts.removeLast();
528 length -= lastPart.length + OVERHEAD;
529 if (elision == null) {
530 elision = "..."; 566 elision = "...";
531 length += ELLIPSIS_SIZE + OVERHEAD; 567 length += ELLIPSIS_SIZE + OVERHEAD;
532 } 568 }
569
570 // If the last two elements were very long, and we have more than
571 // HEAD_COUNT elements in the initial run, drop some to make room for
572 // the last two.
573 while (length > LENGTH_LIMIT && parts.length > HEAD_COUNT) {
574 length -= parts.removeLast().length + OVERHEAD;
575 if (elision == null) {
576 elision = "...";
577 length += ELLIPSIS_SIZE + OVERHEAD;
578 }
579 }
580 if (elision != null) {
581 parts.add(elision);
582 }
583 parts.add(penultimateString);
584 parts.add(ultimateString);
533 } 585 }
534 if (elision != null) {
535 parts.add(elision);
536 }
537 parts.add(penultimateString);
538 parts.add(ultimateString);
539 } 586 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698