Optimizie the insertion of an iterable.

Avoids creating a list on the side, at the cost of an extra copying
inside the typed-data buffer to move the data into place.

R=floitsch@google.com, nweiz@google.com

Review URL: https://codereview.chromium.org//1408253004 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 36fa6b1..6be0b2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,5 @@
+## 1.1.1
+* Optimize `insertAll` with an `Iterable` argument and no end-point.
 ## 1.1.0
 
 * Add `start` and `end` parameters to the `addAll()` and `insertAll()` methods
diff --git a/lib/typed_buffers.dart b/lib/typed_buffers.dart
index ebf5766..c8cc75d 100644
--- a/lib/typed_buffers.dart
+++ b/lib/typed_buffers.dart
@@ -100,10 +100,14 @@
   void insertAll(int index, Iterable<E> values, [int start = 0, int end]) {
     RangeError.checkValidIndex(index, this, "index", _length + 1);
     RangeError.checkNotNegative(start, "start");
-    if (end != null && start > end) {
-      throw new RangeError.range(end, start, null, "end");
+    if (end != null) {
+      if (start > end) {
+        throw new RangeError.range(end, start, null, "end");
+      }
+      if (start == end) return;
     }
 
+
     // If we're adding to the end of the list anyway, use [_addAll]. This lets
     // us avoid converting [values] into a list even if [end] is null, since we
     // can add values iteratively to the end of the list. We can't do so in the
@@ -113,14 +117,54 @@
       return;
     }
 
-    // If we don't know how much room to make for [values], convert it to a list
-    // so we can tell.
-    if (end == null) {
-      if (values is! List) values = values.toList(growable: false);
+    if (end == null && values is List) {
       end = values.length;
     }
+    if (end != null) {
+      _insertKnownLength(index, values, start, end);
+      return;
+    }
 
-    _insertKnownLength(index, values, start, end);
+    // Add elements at end, growing as appropriate, then put them back at
+    // position [index] using flip-by-double-reverse.
+    if (end != null) values = values.take(end);
+    int writeIndex = _length;
+    int skipCount = start;
+    for (var value in values) {
+      if (skipCount > 0) {
+        skipCount--;
+        continue;
+      }
+      if (writeIndex == _buffer.length) {
+        _grow();
+      }
+      _buffer[writeIndex++] = value;
+    }
+    if (skipCount > 0) {
+      throw new StateError("Too few elements");
+    }
+    if (end != null && writeIndex < end) {
+      throw new RangeError.range(end, start, writeIndex, "end");
+    }
+    // Swap [index.._length) and [_length..writeIndex) by double-reversing.
+    _reverse(_buffer, index, _length);
+    _reverse(_buffer, _length, writeIndex);
+    _reverse(_buffer, index, writeIndex);
+    _length = writeIndex;
+    return;
+  }
+
+  // Reverses the range [start..end) of buffer.
+  static void _reverse(List<int> buffer, int start, int end) {
+    end--;  // Point to last element, not after last element.
+    while (start < end) {
+      var first = buffer[start];
+      var last = buffer[end];
+      buffer[end] = first;
+      buffer[start] = last;
+      start++;
+      end--;
+    }
   }
 
   /// Does the same thing as [addAll].
diff --git a/pubspec.yaml b/pubspec.yaml
index 4ca6cb2..552b36e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: typed_data
-version: 1.1.0
+version: 1.1.1
 author: Dart Team <misc@dartlang.org>
 description: Utility functions and classes related to the 'dart:typed_data' library.
 homepage: https://github.com/dart-lang/typed_data