Skip to content

Commit 6e1ff3c

Browse files
committed
feat(skipLast): add higher-order lettable version of skipLast
1 parent baed383 commit 6e1ff3c

File tree

3 files changed

+94
-54
lines changed

3 files changed

+94
-54
lines changed

src/operator/skipLast.ts

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
import { Operator } from '../Operator';
2-
import { Subscriber } from '../Subscriber';
3-
import { ArgumentOutOfRangeError } from '../util/ArgumentOutOfRangeError';
41
import { Observable } from '../Observable';
5-
import { TeardownLogic } from '../Subscription';
2+
import { skipLast as higherOrder } from '../operators/skipLast';
63

74
/**
85
* Skip the last `count` values emitted by the source Observable.
@@ -37,54 +34,5 @@ import { TeardownLogic } from '../Subscription';
3734
* @owner Observable
3835
*/
3936
export function skipLast<T>(this: Observable<T>, count: number): Observable<T> {
40-
return this.lift(new SkipLastOperator(count));
37+
return higherOrder(count)(this);
4138
}
42-
43-
class SkipLastOperator<T> implements Operator<T, T> {
44-
constructor(private _skipCount: number) {
45-
if (this._skipCount < 0) {
46-
throw new ArgumentOutOfRangeError;
47-
}
48-
}
49-
50-
call(subscriber: Subscriber<T>, source: any): TeardownLogic {
51-
if (this._skipCount === 0) {
52-
// If we don't want to skip any values then just subscribe
53-
// to Subscriber without any further logic.
54-
return source.subscribe(new Subscriber(subscriber));
55-
} else {
56-
return source.subscribe(new SkipLastSubscriber(subscriber, this._skipCount));
57-
}
58-
}
59-
}
60-
61-
/**
62-
* We need this JSDoc comment for affecting ESDoc.
63-
* @ignore
64-
* @extends {Ignored}
65-
*/
66-
class SkipLastSubscriber<T> extends Subscriber<T> {
67-
private _ring: T[];
68-
private _count: number = 0;
69-
70-
constructor(destination: Subscriber<T>, private _skipCount: number) {
71-
super(destination);
72-
this._ring = new Array<T>(_skipCount);
73-
}
74-
75-
protected _next(value: T): void {
76-
const skipCount = this._skipCount;
77-
const count = this._count++;
78-
79-
if (count < skipCount) {
80-
this._ring[count] = value;
81-
} else {
82-
const currentIndex = count % skipCount;
83-
const ring = this._ring;
84-
const oldValue = ring[currentIndex];
85-
86-
ring[currentIndex] = value;
87-
this.destination.next(oldValue);
88-
}
89-
}
90-
}

src/operators/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export { reduce } from './reduce';
6161
export { refCount } from './refCount';
6262
export { scan } from './scan';
6363
export { skip } from './skip';
64+
export { skipLast } from './skipLast';
6465
export { subscribeOn } from './subscribeOn';
6566
export { switchAll } from './switchAll';
6667
export { switchMap } from './switchMap';

src/operators/skipLast.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { Operator } from '../Operator';
2+
import { Subscriber } from '../Subscriber';
3+
import { ArgumentOutOfRangeError } from '../util/ArgumentOutOfRangeError';
4+
import { Observable } from '../Observable';
5+
import { TeardownLogic } from '../Subscription';
6+
import { MonoTypeOperatorFunction } from '../interfaces';
7+
8+
/**
9+
* Skip the last `count` values emitted by the source Observable.
10+
*
11+
* <img src="./img/skipLast.png" width="100%">
12+
*
13+
* `skipLast` returns an Observable that accumulates a queue with a length
14+
* enough to store the first `count` values. As more values are received,
15+
* values are taken from the front of the queue and produced on the result
16+
* sequence. This causes values to be delayed.
17+
*
18+
* @example <caption>Skip the last 2 values of an Observable with many values</caption>
19+
* var many = Rx.Observable.range(1, 5);
20+
* var skipLastTwo = many.skipLast(2);
21+
* skipLastTwo.subscribe(x => console.log(x));
22+
*
23+
* // Results in:
24+
* // 1 2 3
25+
*
26+
* @see {@link skip}
27+
* @see {@link skipUntil}
28+
* @see {@link skipWhile}
29+
* @see {@link take}
30+
*
31+
* @throws {ArgumentOutOfRangeError} When using `skipLast(i)`, it throws
32+
* ArgumentOutOrRangeError if `i < 0`.
33+
*
34+
* @param {number} count Number of elements to skip from the end of the source Observable.
35+
* @returns {Observable<T>} An Observable that skips the last count values
36+
* emitted by the source Observable.
37+
* @method skipLast
38+
* @owner Observable
39+
*/
40+
export function skipLast<T>(count: number): MonoTypeOperatorFunction<T> {
41+
return (source: Observable<T>) => source.lift(new SkipLastOperator(count));
42+
}
43+
44+
class SkipLastOperator<T> implements Operator<T, T> {
45+
constructor(private _skipCount: number) {
46+
if (this._skipCount < 0) {
47+
throw new ArgumentOutOfRangeError;
48+
}
49+
}
50+
51+
call(subscriber: Subscriber<T>, source: any): TeardownLogic {
52+
if (this._skipCount === 0) {
53+
// If we don't want to skip any values then just subscribe
54+
// to Subscriber without any further logic.
55+
return source.subscribe(new Subscriber(subscriber));
56+
} else {
57+
return source.subscribe(new SkipLastSubscriber(subscriber, this._skipCount));
58+
}
59+
}
60+
}
61+
62+
/**
63+
* We need this JSDoc comment for affecting ESDoc.
64+
* @ignore
65+
* @extends {Ignored}
66+
*/
67+
class SkipLastSubscriber<T> extends Subscriber<T> {
68+
private _ring: T[];
69+
private _count: number = 0;
70+
71+
constructor(destination: Subscriber<T>, private _skipCount: number) {
72+
super(destination);
73+
this._ring = new Array<T>(_skipCount);
74+
}
75+
76+
protected _next(value: T): void {
77+
const skipCount = this._skipCount;
78+
const count = this._count++;
79+
80+
if (count < skipCount) {
81+
this._ring[count] = value;
82+
} else {
83+
const currentIndex = count % skipCount;
84+
const ring = this._ring;
85+
const oldValue = ring[currentIndex];
86+
87+
ring[currentIndex] = value;
88+
this.destination.next(oldValue);
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)