Skip to content

Commit fe35c56

Browse files
committed
Use more efficient implementation. Fix comment typos.
1 parent 57adf31 commit fe35c56

File tree

3 files changed

+98
-61
lines changed

3 files changed

+98
-61
lines changed

pkgs/collection/lib/src/iterable_extensions.dart

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -75,34 +75,37 @@ extension IterableExtension<T> on Iterable<T> {
7575
/// print([].separated(-1)); // ()
7676
///
7777
/// print([1, 2, 3].separated(
78-
/// -1
78+
/// -1,
7979
/// before: true,
8080
/// )); // (-1, 1, -1, 2, -1, 3)
8181
///
8282
/// print([1].separated(
83-
/// -1
83+
/// -1,
8484
/// before: true,
8585
/// after: true,
8686
/// )); // (-1, 1, -1)
8787
///
8888
/// print([].separated(
89-
/// -1
89+
/// -1,
9090
/// before: true,
9191
/// after: true,
9292
/// )); // ()
9393
/// ```
9494
Iterable<T> separated(T separator,
9595
{bool before = false, bool after = false}) sync* {
96-
const emitBefore = 1;
97-
const emitAfter = 2;
98-
var state = before ? emitBefore : 0;
99-
final afterState = emitBefore | (after ? emitAfter : 0);
100-
for (var element in this) {
101-
if (state & emitBefore != 0) yield separator;
102-
state = afterState;
103-
yield element;
96+
var iterator = this.iterator;
97+
if (iterator.moveNext()) {
98+
if (before) yield separator;
99+
while (true) {
100+
yield iterator.current;
101+
if (iterator.moveNext()) {
102+
yield separator;
103+
} else {
104+
break;
105+
}
106+
}
107+
if (after) yield separator;
104108
}
105-
if (state & emitAfter != 0) yield separator;
106109
}
107110

108111
/// Creates new list with the elements of this list separated by [separator].
@@ -124,32 +127,39 @@ extension IterableExtension<T> on Iterable<T> {
124127
/// print([].separatedList(-1)); // []
125128
///
126129
/// print([1, 2, 3].separatedList(
127-
/// -1
130+
/// -1,
128131
/// before: true,
129132
/// )); // [-1, 1, -1, 2, -1, 3]
130133
///
131134
/// print([1].separatedList(
132-
/// -1
135+
/// -1,
133136
/// before: true,
134137
/// after: true,
135138
/// )); // [-1, 1, -1]
136139
///
137140
/// print([].separatedList(
138-
/// -1
141+
/// -1,
139142
/// before: true,
140143
/// after: true,
141144
/// )); // []
142145
/// ```
143146
List<T> separatedList(T separator,
144147
{bool before = false, bool after = false}) {
145-
var hasElement = false;
146-
return [
147-
for (var element in this) ...[
148-
if (hasElement || (hasElement = true) && before) separator,
149-
element,
150-
],
151-
if (hasElement && after) separator
152-
];
148+
var result = <T>[];
149+
var iterator = this.iterator;
150+
if (iterator.moveNext()) {
151+
if (before) result.add(separator);
152+
while (true) {
153+
result.add(iterator.current);
154+
if (iterator.moveNext()) {
155+
result.add(separator);
156+
} else {
157+
break;
158+
}
159+
}
160+
if (after) result.add(separator);
161+
}
162+
return result;
153163
}
154164

155165
/// The elements that do not satisfy [test].

pkgs/collection/lib/src/list_extensions.dart

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -390,50 +390,58 @@ extension ListExtensions<E> on List<E> {
390390
///
391391
/// Example:
392392
/// ```dart
393-
/// print([1, 2, 3]..insertSeparator(-1)); // [1, -1, 2, -1, 3]
394-
/// print([1]..insertSeparator(-1)); // [1]
395-
/// print([]..insertSeparator(-1)); // []
393+
/// print([1, 2, 3]..separate(-1)); // [1, -1, 2, -1, 3]
394+
/// print([1]..separate(-1)); // [1]
395+
/// print([]..separate(-1)); // []
396396
///
397-
/// print([1, 2, 3]..insertSeparator(
398-
/// -1
397+
/// print([1, 2, 3]..separate(
398+
/// -1,
399399
/// before: true,
400400
/// )); // [-1, 1, -1, 2, -1, 3]
401401
///
402-
/// print([1]..insertSeparator(
403-
/// -1
402+
/// print([1]..separate(
403+
/// -1,
404404
/// before: true,
405405
/// after: true,
406406
/// )); // [-1, 1, -1]
407407
///
408-
/// print([]..insertSeparator(
409-
/// -1
408+
/// print([]..separate(
409+
/// -1,
410410
/// before: true,
411411
/// after: true,
412412
/// )); // []
413413
/// ```
414414
void separate(E separator, {bool before = false, bool after = false}) {
415415
var length = this.length;
416416
if (length == 0) return;
417-
var newLength = length * 2 - 1;
418-
var offset = 0;
419-
if (before) {
420-
newLength++;
421-
offset = 1;
417+
// New position of first element.
418+
var newFirst = before ? 1 : 0;
419+
// New position of last element.
420+
var newLast = length * 2 - (newFirst ^ 1);
421+
422+
var splitIndex = length - newFirst;
423+
var cursor = splitIndex >> 1;
424+
if (splitIndex.isEven) {
425+
add(this[cursor]);
422426
}
423-
if (after) newLength++;
424-
E newElementAt(int index) {
425-
index -= offset;
426-
if (index.isOdd) return separator;
427-
return this[index >> 1];
427+
cursor++;
428+
while (this.length < newLast) {
429+
add(separator);
430+
add(this[cursor++]);
428431
}
432+
assert(cursor == length);
433+
if (after) add(separator);
429434

430-
for (var i = length; i < newLength; i++) {
431-
add(newElementAt(i));
435+
cursor = splitIndex >> 1;
436+
if (splitIndex.isOdd) {
437+
this[--length] = this[cursor];
432438
}
433-
for (var i = length, firstChanged = offset ^ 1; i > firstChanged;) {
434-
--i;
435-
this[i] = newElementAt(i);
439+
cursor--;
440+
for (var i = length; i > 1;) {
441+
this[--i] = separator;
442+
this[--i] = this[cursor--];
436443
}
444+
if (newFirst != 0) this[0] = separator;
437445
}
438446
}
439447

pkgs/collection/test/separate_extensions_test.dart

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -229,20 +229,39 @@ void main() {
229229
});
230230
});
231231
group('Multiple', () {
232-
test('', () {
233-
expect(<int>[1, 2, 3]..separate(42), [1, 42, 2, 42, 3]);
234-
});
235-
test('before', () {
236-
expect(
237-
<int>[1, 2, 3]..separate(42, before: true), [42, 1, 42, 2, 42, 3]);
238-
});
239-
test('after', () {
240-
expect(
241-
<int>[1, 2, 3]..separate(42, after: true), [1, 42, 2, 42, 3, 42]);
242-
});
243-
test('before and after', () {
244-
expect(<int>[1, 2, 3]..separate(42, before: true, after: true),
245-
[42, 1, 42, 2, 42, 3, 42]);
232+
group('odd length', () {
233+
test('', () {
234+
expect(<int>[1, 2, 3]..separate(42), [1, 42, 2, 42, 3]);
235+
});
236+
test('before', () {
237+
expect(<int>[1, 2, 3]..separate(42, before: true),
238+
[42, 1, 42, 2, 42, 3]);
239+
});
240+
test('after', () {
241+
expect(
242+
<int>[1, 2, 3]..separate(42, after: true), [1, 42, 2, 42, 3, 42]);
243+
});
244+
test('before and after', () {
245+
expect(<int>[1, 2, 3]..separate(42, before: true, after: true),
246+
[42, 1, 42, 2, 42, 3, 42]);
247+
});
248+
});
249+
group('even length', () {
250+
test('', () {
251+
expect(<int>[1, 2, 3, 4]..separate(42), [1, 42, 2, 42, 3, 42, 4]);
252+
});
253+
test('before', () {
254+
expect(<int>[1, 2, 3, 4]..separate(42, before: true),
255+
[42, 1, 42, 2, 42, 3, 42, 4]);
256+
});
257+
test('after', () {
258+
expect(<int>[1, 2, 3, 4]..separate(42, after: true),
259+
[1, 42, 2, 42, 3, 42, 4, 42]);
260+
});
261+
test('before and after', () {
262+
expect(<int>[1, 2, 3, 4]..separate(42, before: true, after: true),
263+
[42, 1, 42, 2, 42, 3, 42, 4, 42]);
264+
});
246265
});
247266
});
248267
test('nulls', () {

0 commit comments

Comments
 (0)