Compare commits
6 Commits
v0.1.1
...
83c491ff6f
| Author | SHA1 | Date | |
|---|---|---|---|
| 83c491ff6f | |||
| 94ce32cff3 | |||
| f762717de5 | |||
| 01e2b30248 | |||
| 7ef36ff9fc | |||
| 87a37b96b6 |
8
Makefile
Normal file
8
Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.PHONY: build test
|
||||||
|
|
||||||
|
build:
|
||||||
|
npx esbuild src/index.js --bundle --minify --outfile=dist/index.js --format=esm
|
||||||
|
npx rollup -c
|
||||||
|
|
||||||
|
test:
|
||||||
|
npx vitest
|
||||||
2013
package-lock.json
generated
2013
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,20 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "@sek1ro/iterables",
|
"name": "@sek1ro/iterables",
|
||||||
"version": "0.1.1",
|
"version": "0.1.4",
|
||||||
"description": "A data structures library based on iterators, inspired by libstdc++",
|
"description": "A data structures library based on iterators, inspired by libstdc++",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
"scripts": {
|
|
||||||
"build": "esbuild src/index.js --bundle --minify --outfile=dist/index.js --format=esm",
|
|
||||||
"test": "vitest"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Vlad Litvinov <vlad@sek1.ro>",
|
"author": "Vlad Litvinov <vlad@sek1.ro>",
|
||||||
"license": "LGPL-3.0-only",
|
"license": "LGPL-3.0-only",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"rollup": "^4.45.1",
|
||||||
|
"rollup-plugin-dts": "^6.2.1",
|
||||||
"vitest": "^3.1.1"
|
"vitest": "^3.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
rollup.config.js
Normal file
10
rollup.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { dts } from "rollup-plugin-dts";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
input: 'types/index.d.ts',
|
||||||
|
output: {
|
||||||
|
file: 'dist/index.d.ts',
|
||||||
|
format: 'es',
|
||||||
|
},
|
||||||
|
plugins: [dts()],
|
||||||
|
}
|
||||||
15
src/List.js
15
src/List.js
@ -35,6 +35,16 @@ export class List {
|
|||||||
return this._end.clone()
|
return this._end.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resize(size, value) {
|
||||||
|
if (this._size > size)
|
||||||
|
while (this._size !== size)
|
||||||
|
this.popBack()
|
||||||
|
|
||||||
|
else
|
||||||
|
while (this._size !== size)
|
||||||
|
this.pushBack(value)
|
||||||
|
}
|
||||||
|
|
||||||
_shiftRight(dest, generator) {
|
_shiftRight(dest, generator) {
|
||||||
let prev, res, new_item, item = dest.deref()
|
let prev, res, new_item, item = dest.deref()
|
||||||
|
|
||||||
@ -75,7 +85,7 @@ export class List {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List.from = function (obj) {
|
List.from = function(obj) {
|
||||||
const list = new List()
|
const list = new List()
|
||||||
for (const value of obj) {
|
for (const value of obj) {
|
||||||
list.pushBack(value)
|
list.pushBack(value)
|
||||||
@ -98,6 +108,7 @@ export class ListItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ListIterator {
|
export class ListIterator {
|
||||||
|
|
||||||
constructor(item) {
|
constructor(item) {
|
||||||
this._item = item
|
this._item = item
|
||||||
}
|
}
|
||||||
@ -130,4 +141,4 @@ export class ListIterator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mixinClasses(ListIterator, BidirectionalIterator)
|
mixinClasses(ListIterator, BidirectionalIterator)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { BidirectionalIterator } from "../iterators/Bidirectional"
|
import { BidirectionalIterator } from "../iterators/Bidirectional"
|
||||||
import { satisfiesConcept } from "../utils/concept"
|
import { getCloneFunc, satisfiesConcept } from "../utils/concept"
|
||||||
|
|
||||||
export class SequenceContainer {
|
export class SequenceContainer {
|
||||||
clone() {
|
clone() {
|
||||||
@ -16,6 +16,9 @@ export class SequenceContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get front() {
|
get front() {
|
||||||
|
if (this.empty())
|
||||||
|
throw new Error('front element is undefined')
|
||||||
|
|
||||||
return this.begin().value
|
return this.begin().value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,6 +27,9 @@ export class SequenceContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get back() {
|
get back() {
|
||||||
|
if (this.empty())
|
||||||
|
throw new Error('back element is undefined')
|
||||||
|
|
||||||
return this.end().dec().value
|
return this.end().dec().value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,13 +126,17 @@ export class SequenceContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
return this.toString()
|
let res = []
|
||||||
|
for (const value of this) {
|
||||||
|
res.push(JSON.stringify(value))
|
||||||
|
}
|
||||||
|
return '[ ' + res.join(', ') + ' ]'
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
let res = []
|
let res = []
|
||||||
for (const value of this) {
|
for (const value of this) {
|
||||||
res.push(JSON.stringify(value))
|
res.push(value.toString())
|
||||||
}
|
}
|
||||||
return '[ ' + res.join(', ') + ' ]'
|
return '[ ' + res.join(', ') + ' ]'
|
||||||
}
|
}
|
||||||
@ -147,10 +157,11 @@ export class SequenceContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SequenceContainer.is = function (obj, ...args) {
|
SequenceContainer.is = function(obj, ...args) {
|
||||||
const pure_virtual = [
|
const pure_virtual = [
|
||||||
'move',
|
'move',
|
||||||
'size',
|
'size',
|
||||||
|
'resize',
|
||||||
'begin',
|
'begin',
|
||||||
'end',
|
'end',
|
||||||
'_shiftRight',
|
'_shiftRight',
|
||||||
@ -175,4 +186,4 @@ SequenceContainer.is = function (obj, ...args) {
|
|||||||
'toString',
|
'toString',
|
||||||
]
|
]
|
||||||
return satisfiesConcept(obj, pure_virtual, virtual, ...args)
|
return satisfiesConcept(obj, pure_virtual, virtual, ...args)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export class ForwardIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get value() {
|
get value() {
|
||||||
return this.deref()?.value
|
return this.deref().value
|
||||||
}
|
}
|
||||||
|
|
||||||
set value(value) {
|
set value(value) {
|
||||||
@ -32,4 +32,4 @@ ForwardIterator.is = function (obj, ...args) {
|
|||||||
'neq',
|
'neq',
|
||||||
]
|
]
|
||||||
return satisfiesConcept(obj, pure_virtual, virtual, ...args)
|
return satisfiesConcept(obj, pure_virtual, virtual, ...args)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,4 +31,4 @@ export function satisfiesConcept(obj, pure_virtual, virtual, debug) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,4 +4,4 @@ export function mixinClasses(dest, ...sources) {
|
|||||||
delete properties.constructor
|
delete properties.constructor
|
||||||
Object.defineProperties(dest.prototype, properties)
|
Object.defineProperties(dest.prototype, properties)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,7 @@ test('move, empty', () => {
|
|||||||
|
|
||||||
test('constructor, assign', () => {
|
test('constructor, assign', () => {
|
||||||
expect(new List().size()).toEqual(0)
|
expect(new List().size()).toEqual(0)
|
||||||
expect(new List().back).toEqual(undefined)
|
expect(() => new List().back).toThrow()
|
||||||
expect(listEquArray(new List(null), [null])).toBeTruthy()
|
expect(listEquArray(new List(null), [null])).toBeTruthy()
|
||||||
expect(listEquArray(new List(null, 2), [null, null])).toBeTruthy()
|
expect(listEquArray(new List(null, 2), [null, null])).toBeTruthy()
|
||||||
{
|
{
|
||||||
@ -60,6 +60,19 @@ test('constructor, assign', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('resize', () => {
|
||||||
|
{
|
||||||
|
const list = List.from([1, 2, 3])
|
||||||
|
list.resize(1)
|
||||||
|
expect(listEquArray(list, [1])).toBeTruthy()
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const list = List.from([1])
|
||||||
|
list.resize(3, 2)
|
||||||
|
expect(listEquArray(list, [1, 2, 2])).toBeTruthy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('insert, clone', () => {
|
test('insert, clone', () => {
|
||||||
{
|
{
|
||||||
const list = List.from([1, 2])
|
const list = List.from([1, 2])
|
||||||
@ -134,4 +147,5 @@ test('pushBack, pushFront, popBack, popFront, back, front', () => {
|
|||||||
|
|
||||||
test('toJSON, toString', () => {
|
test('toJSON, toString', () => {
|
||||||
expect(List.from([1, 2]).toJSON()).toEqual('[ 1, 2 ]')
|
expect(List.from([1, 2]).toJSON()).toEqual('[ 1, 2 ]')
|
||||||
})
|
expect(List.from([0n]).toString()).toEqual('[ 0 ]')
|
||||||
|
})
|
||||||
|
|||||||
38
types/List.d.ts
vendored
Normal file
38
types/List.d.ts
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { SequenceContainer } from "./containers/Sequence";
|
||||||
|
import { BidirectionalIterator } from "./iterators/Bidirectional";
|
||||||
|
import { Item } from "./iterators/Forward";
|
||||||
|
|
||||||
|
export class List<T> extends SequenceContainer<T, ListIterator<T>> {
|
||||||
|
/**
|
||||||
|
* empty list
|
||||||
|
*/
|
||||||
|
constructor();
|
||||||
|
/**
|
||||||
|
* list with n similar elements
|
||||||
|
* @param value which will be inserted
|
||||||
|
* @param n count of how many values will be inserted
|
||||||
|
*/
|
||||||
|
constructor(value: T, n?: number);
|
||||||
|
/**
|
||||||
|
* copies range of another list
|
||||||
|
* @param begin of another SequenceContainer<T>
|
||||||
|
* @param end of another SequenceContainer<T>
|
||||||
|
*/
|
||||||
|
constructor(begin: ListIterator<T>, end: ListIterator<T>);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates list from array, string and other iterable object
|
||||||
|
*/
|
||||||
|
static from<T>(obj: Iterable<T>): List<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ListItem<T> extends Item<T> {
|
||||||
|
get next(): ListItem<T>;
|
||||||
|
get prev(): ListItem<T>;
|
||||||
|
|
||||||
|
private constructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ListIterator<T> extends BidirectionalIterator<T> {
|
||||||
|
private constructor();
|
||||||
|
}
|
||||||
79
types/containers/Sequence.d.ts
vendored
Normal file
79
types/containers/Sequence.d.ts
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { ForwardIterator } from "../iterators/Forward";
|
||||||
|
|
||||||
|
export class SequenceContainer<T, It extends ForwardIterator<T>> {
|
||||||
|
move(rhs: SequenceContainer<T, It>): this;
|
||||||
|
size(): number;
|
||||||
|
begin(): It;
|
||||||
|
end(): It;
|
||||||
|
|
||||||
|
clone(): this;
|
||||||
|
copy(rhs: SequenceContainer<T, It>): this;
|
||||||
|
empty(): boolean;
|
||||||
|
/**
|
||||||
|
* @returns direct access to front item's value
|
||||||
|
* @throws Error if size == 0
|
||||||
|
*/
|
||||||
|
get front(): T;
|
||||||
|
set front(value: T);
|
||||||
|
/**
|
||||||
|
* @returns direct access to back item's value
|
||||||
|
* @throws Error if size == 0
|
||||||
|
*/
|
||||||
|
get back(): T;
|
||||||
|
set back(value: T);
|
||||||
|
/**
|
||||||
|
* inserts [begin, end) at dest
|
||||||
|
* @param dest where to insert
|
||||||
|
* @param begin of another SequenceContainer<T>
|
||||||
|
* @param end of another SequenceContainer<T>
|
||||||
|
* @returns iterator right after end iterator
|
||||||
|
*/
|
||||||
|
insert(dest: It, begin: It, end: It): It;
|
||||||
|
/**
|
||||||
|
* inserts [begin, end) at dest
|
||||||
|
* @param dest where to insert
|
||||||
|
* @param value which will be inserted
|
||||||
|
* @param n count of how many values will be inserted
|
||||||
|
* @returns iterator right after last inserted value
|
||||||
|
*/
|
||||||
|
insert(dest: It, value: T, n?: number): It;
|
||||||
|
/**
|
||||||
|
* same as list.clear(); list.insert(list.begin(), ...)
|
||||||
|
* @param begin of another SequenceContainer<T>
|
||||||
|
* @param end of another SequenceContainer<T>
|
||||||
|
* @returns end iterator
|
||||||
|
*/
|
||||||
|
assign(begin: It, end: It): It;
|
||||||
|
/**
|
||||||
|
* same as list.clear(); list.insert(list.begin(), ...)
|
||||||
|
* @param value which will be inserted
|
||||||
|
* @param n count of how many values will be inserted
|
||||||
|
* @returns iterator right after last inserted value
|
||||||
|
*/
|
||||||
|
assign(value: T, n?: number): It;
|
||||||
|
/**
|
||||||
|
* erases [begin, end)
|
||||||
|
* @param begin of erased range
|
||||||
|
* @param end of erased range
|
||||||
|
* @returns iterator right after erased range
|
||||||
|
*/
|
||||||
|
erase(begin: It, end: It): It;
|
||||||
|
/**
|
||||||
|
* erases single item
|
||||||
|
* @param begin which points to erased item
|
||||||
|
* @returns iterator right after erased value
|
||||||
|
*/
|
||||||
|
erase(item: It): It;
|
||||||
|
/**
|
||||||
|
* same as list.erase(list.begin(), list.end())
|
||||||
|
* @returns end iterator
|
||||||
|
*/
|
||||||
|
clear(): It;
|
||||||
|
pushFront(value: T): void;
|
||||||
|
pushBack(value: T): void;
|
||||||
|
popFront(): void;
|
||||||
|
popBack(): void;
|
||||||
|
[Symbol.iterator](): Iterator<T>;
|
||||||
|
toJSON(): string;
|
||||||
|
toString(): string;
|
||||||
|
}
|
||||||
5
types/index.d.ts
vendored
Normal file
5
types/index.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import type { ForwardIterator } from "./iterators/Forward"
|
||||||
|
import type { BidirectionalIterator } from "./iterators/Bidirectional"
|
||||||
|
import type { SequenceContainer } from "./containers/Sequence"
|
||||||
|
import type { List, ListIterator, ListItem } from "./List"
|
||||||
|
export type { ForwardIterator, BidirectionalIterator, SequenceContainer, List, ListIterator, ListItem }
|
||||||
9
types/iterators/Bidirectional.d.ts
vendored
Normal file
9
types/iterators/Bidirectional.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { ForwardIterator } from "./Forward";
|
||||||
|
|
||||||
|
export class BidirectionalIterator<T> extends ForwardIterator<T> {
|
||||||
|
/**
|
||||||
|
* decrements iterator, it doesn't make copy
|
||||||
|
* @returns {this}
|
||||||
|
*/
|
||||||
|
dec(): this;
|
||||||
|
}
|
||||||
24
types/iterators/Forward.d.ts
vendored
Normal file
24
types/iterators/Forward.d.ts
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
export class Item<T> {
|
||||||
|
value: T
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ForwardIterator<T> {
|
||||||
|
clone(): ForwardIterator<T>;
|
||||||
|
copy(rhs: ForwardIterator<T>): this;
|
||||||
|
deref(): Item<T>;
|
||||||
|
eq(rhs: ForwardIterator<T>): boolean;
|
||||||
|
/**
|
||||||
|
* increments iterator, it doesn't make copy
|
||||||
|
* @returns {this}
|
||||||
|
*/
|
||||||
|
inc(): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* move-semantics, here it just copies rhs into this
|
||||||
|
* @returns {this}
|
||||||
|
*/
|
||||||
|
move(rhs: ForwardIterator<T>): this;
|
||||||
|
get value(): T;
|
||||||
|
set value(value: T);
|
||||||
|
neq(rhs: ForwardIterator<T>): boolean;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user