Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create new data structure called stretch #1693

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
72 changes: 72 additions & 0 deletions __tests__/Stretch.ts
@@ -0,0 +1,72 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

///<reference path='../resources/jest.d.ts'/>

import * as jasmineCheck from 'jasmine-check';
jasmineCheck.install();

import { Stretch } from '../';

describe('Stretch', () => {
it('fixed stretch', () => {
const v = Stretch(5, 3);
expect(v.size).toBe(3);
expect(v.first()).toBe(2);
expect(v.rest().toArray()).toEqual([5, 8]);
expect(v.last()).toBe(8);
expect(v.butLast().toArray()).toEqual([2, 5]);
expect(v.toArray()).toEqual([2, 5, 8]);
});

it('ends and front', () => {
const v = Stretch(5, 3, 4);
expect(v.size).toBe(3);
expect(v.first()).toBe(2);
expect(v.rest().toArray()).toEqual([5, 9]);
expect(v.last()).toBe(9);
expect(v.butLast().toArray()).toEqual([2, 5]);
expect(v.toArray()).toEqual([2, 5, 9]);
});

it('slices stretch', () => {
const v = Stretch(5, 3, 4);
const s = v.slice(0, 2);
expect(s.size).toBe(2);
expect(s.toArray()).toEqual([2, 5]);
});

it('one value', () => {
const v = Stretch(5, 3, 4);
const s = v.slice(0, 1);
expect(s.size).toBe(1);
expect(s.toArray()).toEqual([2]);
});

it('maps values', () => {
const r = Stretch(5, 3).map(v => v * v);
expect(r.toArray()).toEqual([4, 25, 64]);
});

it('reduces values', () => {
const v = Stretch(5, 3);
const r = v.reduce<number>((a, b) => a + b, 0);
expect(r).toEqual(15);
});

it('can be float', () => {
const v = Stretch(3.5, 1.5, 2.5);
expect(v.size).toBe(3);
expect(v.toArray()).toEqual([2, 3.5, 6]);
});

it('can be negative', () => {
const v = Stretch(-5, -5, -6);
expect(v.size).toBe(3);
expect(v.toArray()).toEqual([0, -5, -11]);
});
});
3 changes: 3 additions & 0 deletions src/Immutable.js
Expand Up @@ -15,6 +15,7 @@ import { Set } from './Set';
import { Record } from './Record';
import { Range } from './Range';
import { Repeat } from './Repeat';
import { Stretch } from './Stretch';
import { is } from './is';
import { fromJS } from './fromJS';

Expand Down Expand Up @@ -71,6 +72,7 @@ export default {
Record: Record,
Range: Range,
Repeat: Repeat,
Stretch: Stretch,

is: is,
fromJS: fromJS,
Expand Down Expand Up @@ -125,6 +127,7 @@ export {
Record,
Range,
Repeat,
Stretch,
is,
fromJS,
hash,
Expand Down
152 changes: 152 additions & 0 deletions src/Stretch.js
@@ -0,0 +1,152 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { wholeSlice, resolveBegin, resolveEnd } from './TrieUtils';
import { IndexedSeq } from './Seq';
import invariant from './utils/invariant';
import deepEqual from './utils/deepEqual';
import { Iterator, iteratorValue, iteratorDone } from './Iterator';

/**
* Returns a lazy seq of base - ends, base, base + front,
* if front is not provided it returns base + ends,
* `base` and `ends` both default to 1
*/
export class Stretch {
constructor(base, ends, front) {
if (!(this instanceof Stretch)) {
return new Stretch(base, ends, front);
}
invariant(
base !== Infinity || ends !== Infinity || front !== Infinity,
`Must be a finite number`
);
invariant(base !== undefined, `Base is required`);
ends = ends === undefined ? 1 : ends;
front = front === undefined ? ends : front;
this._base = base;
this._start = base - ends;
this._end = base + front;
this.size = 3;
/*when i tried extending IndexedSeq or ArraySeq and calling super
the tests __tests__/Stretch.ts returned [5, 8, undefined] instead of 2, 5, 8]
and [5, 9, undefined] instead of [2, 5, 9]*/
return new IndexedSeq([this._start, this._base, this._end]);
}
toString() {
return `[${this._start}, ${this._base}, ${this._end}]`;
}

get(index, notSetValue) {
return index === 0
? this._start
: index === 1
? this._base
: index === 2
? this._end
: notSetValue;
}

includes(searchValue) {
return (
searchValue === this._start ||
searchValue === this._base ||
searchValue === this._end
);
}

slice(begin, end) {
if (wholeSlice(begin, end, this.size)) {
return this;
}
begin = resolveBegin(begin, this.size);
end = resolveEnd(end, this.size);
return end <= begin
? new IndexedSeq([])
: end - begin === 1
? new IndexedSeq([this.get(begin)])
: new IndexedSeq([this.get(begin), this.get(begin + 1)]);
}

indexOf(searchValue) {
return searchValue === this._start
? 0
: searchValue === this._base
? 1
: searchValue === this._end
? 2
: -1;
}
/*we can't return indexOf for lastIndexOf because ends and front can
be be different values*/
lastIndexOf(searchValue) {
return searchValue === this._end
? 2
: searchValue === this._base
? 1
: searchValue === this._start
? 0
: -1;
}

__iterate(fn, reverse) {
const size = 3;
let value = reverse ? this._end : this._start;
let i = 0;
value += reverse ? -(this._end - this._base) : this._base - this._start;
if (fn(value, reverse ? size - ++i : i++, this) === false) {
return i;
}
value += reverse ? -(this._base - this._start) : this._end - this._base;
if (fn(value, reverse ? size - ++i : i++, this) === false) {
return i;
}
return i;
}

__iterator(type, reverse) {
const array = [this._start, this._base, this._end];
const size = 3;
let i = 0;
return new Iterator(() => {
if (i === size) {
return iteratorDone();
}
const ii = reverse ? size - ++i : i++;
return iteratorValue(type, ii, array[ii]);
});
}

reverse() {
return new Stretch(this._base, -this._ends, -this._front);
}

interpose(separator) {
return new IndexedSeq([
this._start,
separator,
this._base,
separator,
this._end,
]);
}

rest() {
return new IndexedSeq([this._base, this._end]);
}

butLast() {
return new IndexedSeq([this._start, this._base]);
}

equals(other) {
return other instanceof Stretch
? this._start === other._start &&
this._end === other._end &&
this._base === other._base
: deepEqual(this, other);
}
}
17 changes: 17 additions & 0 deletions type-definitions/Immutable.d.ts
Expand Up @@ -2203,6 +2203,23 @@ declare module Immutable {
*/
export function Repeat<T>(value: T, times?: number): Seq.Indexed<T>;

/**
* Returns a Seq.Indexed with `base` - `ends`, `base`, and `base` + `front`, if
* front is not provided it returns `base` + `ends`, `base` is required and `ends`
* defaults to 1
*
* Note: `Stretch` is a factory function and not a class, and does not use the
* `new` keyword during construction.
*
* ```js
* const { Stretch } = require('immutable')
* Stretch(10, 5) // [5, 10, 15]
* Stretch(10, 5, 3) // [5, 10, 13]
* Stretch(5) // [4, 5, 6]
* ```
*/
export function Stretch(base: number, ends?: number, front?: number): Seq.Indexed<number>;


/**
* A record is similar to a JS object, but enforces a specific set of allowed
Expand Down
3 changes: 3 additions & 0 deletions type-definitions/immutable.js.flow
Expand Up @@ -1380,6 +1380,7 @@ declare class Stack<+T> extends IndexedCollection<T> {

declare function Range(start?: number, end?: number, step?: number): IndexedSeq<number>;
declare function Repeat<T>(value: T, times?: number): IndexedSeq<T>;
declare function Stretch(base: number, ends?: number, front?: number): IndexedSeq<number>;

// The type of a Record factory function.
type RecordFactory<Values: Object> = Class<RecordInstance<Values>>;
Expand Down Expand Up @@ -1581,6 +1582,7 @@ export {
OrderedSet,
Range,
Repeat,
Stretch
Record,
Set,
Stack,
Expand Down Expand Up @@ -1624,6 +1626,7 @@ export default {
OrderedSet,
Range,
Repeat,
Stretch,
Record,
Set,
Stack,
Expand Down
8 changes: 7 additions & 1 deletion type-definitions/tests/immutable-flow.js
Expand Up @@ -18,6 +18,7 @@ import Immutable, {
Seq,
Range,
Repeat,
Stretch,
Record,
OrderedMap,
OrderedSet,
Expand Down Expand Up @@ -64,6 +65,7 @@ const ImmutableSet = Immutable.Set
const ImmutableKeyedCollection: KeyedCollection<*, *> = Immutable.Collection.Keyed()
const ImmutableRange = Immutable.Range
const ImmutableRepeat = Immutable.Repeat
const ImmutableStretch = Immutable.Stretch
const ImmutableIndexedSeq: IndexedSeq<*> = Immutable.Seq.Indexed()

const Immutable2List = Immutable2.List
Expand All @@ -73,6 +75,7 @@ const Immutable2Set = Immutable2.Set
const Immutable2KeyedCollection: Immutable2.KeyedCollection<*, *> = Immutable2.Collection.Keyed()
const Immutable2Range = Immutable2.Range
const Immutable2Repeat = Immutable2.Repeat
const Immutable2Stretch = Immutable2.Stretch
const Immutable2IndexedSeq: Immutable2.IndexedSeq<*> = Immutable2.Seq.Indexed()

var defaultExport: List<*> = Immutable.List();
Expand Down Expand Up @@ -884,17 +887,20 @@ numberStack = Stack([1]).flatMap((value, index, iter) => ['a'])
numberStack = Stack([1]).flatten()
numberStack = Stack(['a']).flatten()

/* Range & Repeat */
/* Range & Repeat & Stretch */

// `{}` provide namespaces
{ const numberSequence: IndexedSeq<number> = Range(0, 0, 0) }
{ const numberSequence: IndexedSeq<number> = Repeat(1, 5) }
{ const numberSequence: IndexedSeq<number> = Stretch(5, 3) }

{ const stringSequence: IndexedSeq<string> = Repeat('a', 5) }
// $ExpectError
{ const stringSequence: IndexedSeq<string> = Repeat(0, 1) }
// $ExpectError
{ const stringSequence: IndexedSeq<string> = Range(0, 0, 0) }
// $ExpectError
{ const stringSequence: IndexedSeq<string> = Stretch('a', 3) }

/* Seq */

Expand Down
3 changes: 3 additions & 0 deletions type-definitions/ts-tests/exports.ts
Expand Up @@ -15,6 +15,7 @@ import {
OrderedSet,
Range,
Repeat,
Stretch,
Seq,
Set,
Stack,
Expand All @@ -28,6 +29,7 @@ OrderedSet; // $ExpectType typeof OrderedSet
// TODO: Turn on once https://github.com/Microsoft/dtslint/issues/19 is resolved.
Range; // $ ExpectType (start?: number | undefined, end?: number | undefined, step?: number | undefined) => Indexed<number>
Repeat; // $ExpectType <T>(value: T, times?: number | undefined) => Indexed<T>
Stretch; // $ExpectType (base: number, ends?: number | undefined, front?: number | undefined) => Indexed<number>
Seq; // $ExpectType typeof Seq
Set; // $ExpectType typeof Set
Stack; // $ExpectType typeof Stack
Expand All @@ -43,6 +45,7 @@ Immutable.OrderedSet; // $ExpectType typeof OrderedSet
// TODO: Turn on once https://github.com/Microsoft/dtslint/issues/19 is resolved.
Immutable.Range; // $ ExpectType (start?: number | undefined, end?: number | undefined, step?: number | undefined) => Indexed<number>
Immutable.Repeat; // $ExpectType <T>(value: T, times?: number | undefined) => Indexed<T>
Immutable.Stretch; // $ExpectType (base: number, ends?: number | undefined, front?: number | undefined) => Indexed<number>
Immutable.Seq; // $ExpectType typeof Seq
Immutable.Set; // $ExpectType typeof Set
Immutable.Stack; // $ExpectType typeof Stack
Expand Down
17 changes: 17 additions & 0 deletions type-definitions/ts-tests/stretch.ts
@@ -0,0 +1,17 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import { Stretch } from '../../';

{ // #constructor

// $ExpectType Indexed<number>
Stretch(5, 3);

// $ExpectError
Stretch('a', 3);
}