pax_global_header 0000666 0000000 0000000 00000000064 14306031657 0014517 g ustar 00root root 0000000 0000000 52 comment=52297ad37f2ef4da67ce341957badd264ae2c0f8
js-sdsl-4.1.4/ 0000775 0000000 0000000 00000000000 14306031657 0013104 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/.all-contributorsrc 0000664 0000000 0000000 00000001060 14306031657 0016732 0 ustar 00root root 0000000 0000000 {
"projectName": "js-sdsl",
"projectOwner": "ZLY201",
"repoType": "github",
"repoHost": "https://github.com",
"files": [
"README.md"
],
"imageSize": 100,
"commit": true,
"commitConvention": "eslint",
"contributors": [
{
"login": "redboltz",
"name": "Takatoshi Kondo",
"avatar_url": "https://avatars.githubusercontent.com/u/275959?v=4",
"profile": "https://www.linkedin.com/in/takatoshi-kondo-02a91410/",
"contributions": [
"code",
"test"
]
}
],
"contributorsPerLine": 7
}
js-sdsl-4.1.4/.commitlintrc.json 0000664 0000000 0000000 00000001524 14306031657 0016563 0 ustar 00root root 0000000 0000000 {
"parserPreset": "conventional-changelog-conventionalcommits",
"rules": {
"body-leading-blank": [1, "always"],
"body-max-line-length": [2, "always", 100],
"footer-leading-blank": [1, "always"],
"footer-max-line-length": [2, "always", 100],
"header-max-length": [2, "always", 100],
"subject-case": [
2,
"never",
[
"sentence-case", "start-case", "pascal-case", "upper-case"
]
],
"subject-empty": [2, "never"],
"subject-full-stop": [2, "never", "."],
"type-case": [2, "always", "lower-case"],
"type-empty": [2, "never"],
"type-enum": [
2,
"always",
[
"build",
"chore",
"ci",
"docs",
"feat",
"fix",
"perf",
"refactor",
"revert",
"style",
"test"
]
]
}
}
js-sdsl-4.1.4/.editorconfig 0000664 0000000 0000000 00000000266 14306031657 0015565 0 ustar 00root root 0000000 0000000 root = true
[*]
indent_size = 2
charset = utf-8
end_of_line = lf
indent_style = space
insert_final_newline = true
[*.{js,ts}]
max_line_length = 100
trim_trailing_whitespace = true
js-sdsl-4.1.4/.eslintignore 0000664 0000000 0000000 00000000076 14306031657 0015612 0 ustar 00root root 0000000 0000000 .github/
.husky/
.vscode/
coverage/
dist/
docs/
node_modules/
js-sdsl-4.1.4/.eslintrc.json 0000664 0000000 0000000 00000023647 14306031657 0015714 0 ustar 00root root 0000000 0000000 {
"env": {
"browser": true,
"amd": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:compat/recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2016,
"sourceType": "module"
},
"plugins": [
"compat",
"@typescript-eslint"
],
"ignorePatterns": [
"node_modules/",
"dist/"
],
"rules": {
"compat/compat": "error",
"no-var": "error",
"object-shorthand": [
"error",
"properties"
],
"accessor-pairs": [
"error",
{
"setWithoutGet": true,
"enforceForClassMembers": true
}
],
"array-bracket-spacing": [
"error",
"never"
],
"array-callback-return": [
"error",
{
"allowImplicit": false,
"checkForEach": false
}
],
"arrow-spacing": [
"error",
{
"before": true,
"after": true
}
],
"block-spacing": [
"error",
"always"
],
"brace-style": [
"error",
"1tbs"
],
"camelcase": [
"error",
{
"allow": [
"^UNSAFE_"
],
"properties": "never",
"ignoreGlobals": true
}
],
"comma-dangle": [
"error",
{
"arrays": "never",
"objects": "never",
"imports": "never",
"exports": "never",
"functions": "never"
}
],
"comma-spacing": [
"error",
{
"before": false,
"after": true
}
],
"comma-style": [
"error",
"last"
],
"computed-property-spacing": [
"error",
"never",
{
"enforceForClassMembers": true
}
],
"constructor-super": "error",
"curly": [
"error",
"multi-line"
],
"default-case-last": "error",
"dot-location": [
"error",
"property"
],
"dot-notation": [
"error",
{
"allowKeywords": true
}
],
"eol-last": "error",
"eqeqeq": [
"error",
"always",
{
"null": "ignore"
}
],
"func-call-spacing": [
"error",
"never"
],
"generator-star-spacing": [
"error",
{
"before": true,
"after": true
}
],
"indent": [
"error",
2
],
"key-spacing": [
"error",
{
"beforeColon": false,
"afterColon": true
}
],
"keyword-spacing": [
"error",
{
"before": true,
"after": true
}
],
"lines-between-class-members": [
"error",
"never"
],
"max-len": [
"error",
{
"code": 100,
"comments": 120,
"ignoreUrls": true
}
],
"multiline-ternary": [
"error",
"always-multiline"
],
"new-cap": [
"error",
{
"newIsCap": true,
"capIsNew": false,
"properties": true
}
],
"new-parens": "error",
"no-array-constructor": "error",
"no-async-promise-executor": "error",
"no-caller": "error",
"no-case-declarations": "error",
"no-class-assign": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": "error",
"no-const-assign": "error",
"no-constant-condition": [
"error",
{
"checkLoops": false
}
],
"no-control-regex": "error",
"no-debugger": "error",
"no-delete-var": "error",
"no-dupe-args": "error",
"no-dupe-class-members": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-useless-backreference": "error",
"no-empty": [
"error",
{
"allowEmptyCatch": true
}
],
"no-empty-character-class": "error",
"no-empty-pattern": "error",
"no-eval": "error",
"no-ex-assign": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-boolean-cast": "error",
"no-extra-parens": [
"error",
"functions"
],
"no-fallthrough": "error",
"no-floating-decimal": "error",
"no-func-assign": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"no-import-assign": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-iterator": "error",
"no-labels": [
"error",
{
"allowLoop": false,
"allowSwitch": false
}
],
"no-lone-blocks": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"no-prototype-builtins": "error",
"no-useless-catch": "error",
"no-mixed-operators": [
"error",
{
"groups": [
[
"==",
"!=",
"===",
"!==",
">",
">=",
"<",
"<="
],
[
"&&",
"||"
],
[
"in",
"instanceof"
]
],
"allowSamePrecedence": true
}
],
"no-mixed-spaces-and-tabs": "error",
"no-multi-spaces": "error",
"no-multi-str": "error",
"no-multiple-empty-lines": [
"error",
{
"max": 1,
"maxEOF": 0
}
],
"no-new": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-new-symbol": "error",
"no-new-wrappers": "error",
"no-obj-calls": "error",
"no-octal": "error",
"no-octal-escape": "error",
"no-proto": "error",
"no-redeclare": [
"error",
{
"builtinGlobals": false
}
],
"no-regex-spaces": "error",
"no-return-assign": [
"error",
"except-parens"
],
"no-self-assign": [
"error",
{
"props": true
}
],
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-tabs": "error",
"no-template-curly-in-string": "error",
"no-this-before-super": "error",
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-unexpected-multiline": "error",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": [
"error",
{
"defaultAssignment": false
}
],
"no-unreachable": "error",
"no-unreachable-loop": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unused-expressions": [
"error",
{
"allowShortCircuit": true,
"allowTernary": true,
"allowTaggedTemplates": true
}
],
"no-unused-vars": [
"error",
{
"args": "none",
"caughtErrors": "none",
"ignoreRestSiblings": true,
"vars": "all"
}
],
"no-useless-call": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-useless-escape": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-void": "error",
"no-whitespace-before-property": "error",
"no-with": "error",
"object-curly-newline": [
"error",
{
"multiline": true,
"consistent": true
}
],
"object-curly-spacing": [
"error",
"always"
],
"object-property-newline": [
"error",
{
"allowMultiplePropertiesPerLine": true
}
],
"one-var": [
"error",
{
"initialized": "never"
}
],
"operator-linebreak": [
"error",
"after",
{
"overrides": {
"?": "before",
":": "before",
"|>": "before"
}
}
],
"padded-blocks": [
"error",
{
"blocks": "never",
"switches": "never",
"classes": "never"
}
],
"prefer-const": [
"error",
{
"destructuring": "all"
}
],
"prefer-promise-reject-errors": "error",
"prefer-regex-literals": [
"error",
{
"disallowRedundantWrapping": true
}
],
"quote-props": [
"error",
"as-needed"
],
"quotes": [
"error",
"single"
],
"rest-spread-spacing": [
"error",
"never"
],
"semi": [
"error",
"always"
],
"semi-spacing": [
"error",
{
"before": false,
"after": true
}
],
"space-before-blocks": [
"error",
"always"
],
"space-before-function-paren": [
"error",
{
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}
],
"space-in-parens": [
"error",
"never"
],
"space-infix-ops": "error",
"space-unary-ops": [
"error",
{
"words": true,
"nonwords": false
}
],
"spaced-comment": [
"error",
"always",
{
"line": {
"markers": [
"*package",
"!",
"/",
",",
"="
]
},
"block": {
"balanced": true,
"markers": [
"*package",
"!",
",",
":",
"::",
"flow-include"
],
"exceptions": [
"*"
]
}
}
],
"symbol-description": "error",
"template-curly-spacing": [
"error",
"never"
],
"template-tag-spacing": [
"error",
"never"
],
"unicode-bom": [
"error",
"never"
],
"use-isnan": [
"error",
{
"enforceForSwitchCase": true,
"enforceForIndexOf": true
}
],
"valid-typeof": [
"error",
{
"requireStringLiterals": true
}
],
"wrap-iife": [
"error",
"any",
{
"functionPrototypeMethods": true
}
],
"yield-star-spacing": [
"error",
"both"
],
"yoda": [
"error",
"never"
],
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-this-alias": "off"
}
}
js-sdsl-4.1.4/.github/ 0000775 0000000 0000000 00000000000 14306031657 0014444 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/.github/CONTRIBUTING.md 0000664 0000000 0000000 00000005651 14306031657 0016704 0 ustar 00root root 0000000 0000000 # Js-sdsl Contributing Guide
Hi! I'm really excited that you are interested in contributing to js-sdsl. Before submitting your contribution, please make sure to take a moment and read through the following guidelines:
- [Code of Conduct](https://github.com/js-sdsl/js-sdsl/blob/main/CODE_OF_CONDUCT.md)
- [Issue Reporting Guidelines](#issue-reporting-guidelines)
- [Pull Request Guidelines](#pull-request-guidelines)
- [Development Setup](#development-setup)
- [Project Structure](#project-structure)
## Issue Reporting Guidelines
- Always use issue-template to create new issues.
## Pull Request Guidelines
- The `main` branch is just a snapshot of the latest stable release. All development should be done in dedicated branches. **Do not submit PRs against the `main` branch.**
- Checkout a topic branch from the relevant branch, e.g. `dev`, and merge back against that branch.
- Work in the `src` folder and **DO NOT** check in `dist` in the commits.
- It's OK to have multiple small commits as you work on the PR - GitHub will automatically squash it before merging.
- Make sure `yarn test` passes. (see [development setup](#development-setup))
- If adding a new feature:
- Add accompanying test case in folders `check` and `performance` .
- Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.
- If fixing bug:
- If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `update entities encoding/decoding (fix #3899)`.
- Provide a detailed description of the bug in the PR. Live demo preferred.
- Add appropriate test coverage if applicable.
## Development Setup
You will need [Node.js](http://nodejs.org) **version 14+** and [yarn](https://yarnpkg.com/).
After cloning the repo, run:
```bash
$ yarn install
```
### Committing Changes
Please follow the commit specification. See [`.commitlintrc.json`](https://github.com/js-sdsl/js-sdsl/blob/main/.commitlintrc.json) get help.
### Commonly used NPM scripts
```bash
# run all tests
$ yarn test
# run unit tests
$ yarn test:unit
# run performance tests
$ yarn test:performance
# build all dist files
$ yarn build
# build specific mode including es module, commonJS and universal module definition
$ yarn build:{build_mode}
```
There are some other scripts available in the `scripts` section of the `package.json` file.
## Project Structure
- **`test`**: contains all unit tests.
- **`performance`**: contains all performance tests.
- **`src`**: contains the source code.
All our source files are written in typescript, please make sure your submissions have strict type deduction and follow eslint specifications.
## Credits
Thank you to all the people who have already contributed to js-sdsl!
js-sdsl-4.1.4/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 14306031657 0016627 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/.github/ISSUE_TEMPLATE/bug_report.md 0000664 0000000 0000000 00000001027 14306031657 0021321 0 ustar 00root root 0000000 0000000 ---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
js-sdsl-4.1.4/.github/ISSUE_TEMPLATE/custom.md 0000664 0000000 0000000 00000000176 14306031657 0020467 0 ustar 00root root 0000000 0000000 ---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''
---
js-sdsl-4.1.4/.github/ISSUE_TEMPLATE/feature_request.md 0000664 0000000 0000000 00000001123 14306031657 0022351 0 ustar 00root root 0000000 0000000 ---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
js-sdsl-4.1.4/.github/PULL_REQUEST_TEMPLATE.md 0000664 0000000 0000000 00000002145 14306031657 0020247 0 ustar 00root root 0000000 0000000
**What kind of change does this PR introduce?** (check at least one)
- [ ] Bugfix
- [ ] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Build-related changes
- [ ] Other, please describe:
**Does this PR introduce a breaking change?** (check one)
- [ ] Yes
- [ ] No
If yes, please describe the impact and migration path for existing applications:
**The PR fulfills these requirements:**
- [ ] It's submitted to the `dev` branch, **not** the `main` branch
- [ ] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number)
- [ ] All tests are passing
- [ ] New/updated tests are included
If adding a **new feature**, the PR's description includes:
- [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)
**Other information:**
js-sdsl-4.1.4/.github/workflows/ 0000775 0000000 0000000 00000000000 14306031657 0016501 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/.github/workflows/build.yml 0000664 0000000 0000000 00000004515 14306031657 0020330 0 ustar 00root root 0000000 0000000 name: js-sdsl CI
on:
push:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Use node.js lts/Gallium
uses: actions/setup-node@v3
with:
node-version: lts/Gallium
cache: 'yarn'
- name: Install dependencies
run: yarn install
- name: Run test
run: yarn test
- name: Save performance test result
uses: actions/upload-artifact@v3
with:
name: performance.md
path: dist/performance
- name: Coveralls report
uses: coverallsapp/github-action@master
with:
github-token: ${{ github.token }}
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Install dependencies
run: yarn install
- name: Download performance test result
uses: actions/download-artifact@v3
with:
name: performance.md
- name: Generate type documentation
run: yarn generate && mv README.md README.zh-CN.md performance.md docs/
- name: Deploy to github pages
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: docs
branch: gh-pages
publish:
needs: test
runs-on: ubuntu-latest
if: ${{ contains(github.event.head_commit.message, 'publish@') }}
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Install dependencies
run: yarn install
- name: Build
run: yarn build
- name: Publish to npm
run: yarn publish
env:
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
release:
needs: test
runs-on: ubuntu-latest
if: ${{ contains(github.event.head_commit.message, 'publish@') }}
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Read package.json
uses: tyankatsu0105/read-package-version-actions@v1
id: package-version
- name: Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
tag_name: v${{ steps.package-version.outputs.version }}
release_name: v${{ steps.package-version.outputs.version }}
prerelease: false
js-sdsl-4.1.4/.github/workflows/codeql-analysis.yml 0000664 0000000 0000000 00000005167 14306031657 0022325 0 ustar 00root root 0000000 0000000 # For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches:
- dev
- main
pull_request:
branches:
- dev
- main
schedule:
- cron: '28 17 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
js-sdsl-4.1.4/.github/workflows/lint.yml 0000664 0000000 0000000 00000001046 14306031657 0020173 0 ustar 00root root 0000000 0000000 name: lint-code
on:
push:
branches:
- dev
- main
pull_request:
branches:
- dev
- main
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@master
with:
fetch-depth: 0
- name: Install dependencies
run: yarn install
- name: Lint code
run: yarn lint
- name: Lint commit
uses: wagoid/commitlint-github-action@v5
with:
configFile: .commitlintrc.json
failOnWarnings: true
js-sdsl-4.1.4/.github/workflows/test.yml 0000664 0000000 0000000 00000001163 14306031657 0020204 0 ustar 00root root 0000000 0000000 name: Js-sdsl test CI
on:
push:
branches:
- dev
pull_request:
branches:
- dev
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Use node.js lts/Gallium
uses: actions/setup-node@v3
with:
node-version: lts/Gallium
cache: 'yarn'
- name: Install dependencies
run: yarn install
- name: Run test
run: yarn test
- name: Coveralls report
uses: coverallsapp/github-action@master
with:
github-token: ${{ github.token }}
js-sdsl-4.1.4/.gitignore 0000664 0000000 0000000 00000000145 14306031657 0015074 0 ustar 00root root 0000000 0000000 .vscode/
.idea/
dist/
docs/
coverage/
node_modules/
.eslintcache
.npmignore
.npmrc
.yarnrc
.DS_Store
js-sdsl-4.1.4/.husky/ 0000775 0000000 0000000 00000000000 14306031657 0014325 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/.husky/commit-msg 0000775 0000000 0000000 00000000135 14306031657 0016326 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint --edit "$1"
js-sdsl-4.1.4/.husky/pre-commit 0000775 0000000 0000000 00000000101 14306031657 0016317 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
lint-staged
js-sdsl-4.1.4/CHANGELOG.md 0000664 0000000 0000000 00000006554 14306031657 0014727 0 ustar 00root root 0000000 0000000 # Change Log
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
## [4.1.4] - 2022.09.07
### Added
- Add some notes.
### Changed
- Optimize hash container.
- Abstracting out the hash container.
### Fixed
- Fixed tree get height function return one larger than the real height.
- Tree-shaking not work in ES module.
- `Queue` and `Deque` should return `undefined` when container is empty.
## [4.1.4-beta.0] - 2022.08.31
### Added
- Add function update key by iterator.
- Add iterator copy function to get a copy of itself.
- Add insert by iterator hint function in tree container.
### Changed
- Changed OrderedMap's iterator pointer get from `Object.defineProperty'` to `Proxy`.
- Improve iterator performance by remove some judgment.
- Change iterator type description from `normal` and `reverse` to boolean.
## [4.1.2-beta.0] - 2022.08.27
### Added
- Make `SequentialContainer` and `TreeBaseContainer` export in the index.
### Changed
- Change rbTree binary search from recursive to loop implementation (don't effect using).
- Reduce memory waste during deque initialization.
## Fixed
- Fixed priority queue not dereference on pop.
## [4.1.1] - 2022.08.23
### Fixed
- Forgot to reset root node on rotation in red-black tree delete operation.
- Fix iterator invalidation after tree container removes iterator.
## [4.1.0] - 2022.08.21
### Changed
- Change some functions from recursive to loop implementation (don't effect using).
- Change some iterator function parameter type.
- Change commonjs target to `es6`.
- Change `Deque` from sequential queue to circular queue.
- Optimize so many places (don't affect using).
### Fixed
- Fix `Vector` length bugs.
## [4.0.3] - 2022-08-13
### Changed
- Change `if (this.empty())` to `if (!this.length)`.
- Change some unit test.
- Change class type and optimized type design
### Fixed
- Fix can push undefined to deque.
## [4.0.0] - 2022-07-30
### Changed
- Remove InternalError error as much as possible (don't affect using).
- Change `HashSet` api `eraseElementByValue`'s name to `eraseElementByKey`.
- Change some unit tests to improve coverage (don't affect using).
## [4.0.0-beta.0] - 2022-07-24
### Added
- Complete test examples (don't effect using).
- The error thrown is standardized, you can catch it according to the error type.
### Changed
- Refactor all container from function to class (don't affect using).
- Abstracting tree containers and hash containers, change `Set`'s and `Map`'s name to `OrderedSet` and `OrderedMap` to distinguish it from the official container.
- Change `OrderedSet` api `eraseElementByValue`'s name to `eraseElementByKey`.
### Fixed
- Fixed so many bugs.
## [3.0.0-beta.0] - 2022-04-29
### Added
- Bidirectional iterator is provided for all containers except Stack, Queue, HashSet and HashMap.
- Added begin, end, rBegin and rEnd functions to some containers for using iterator.
- Added `eraseElementByIterator` function.
### Changed
- Changed Pair type `T, K` to `K, V` (don't affect using).
- Changed `find`, `lowerBound`, `upperBound`, `reverseLowerBound` and `reverseUpperBound` function's returned value to `Iterator`.
### Fixed
- Fixed an error when the insert value was 0.
- Fixed the problem that the lower version browser does not recognize symbol Compilation error caused by iterator.
js-sdsl-4.1.4/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000012142 14306031657 0015703 0 ustar 00root root 0000000 0000000 # Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
951711127@qq.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
js-sdsl-4.1.4/LICENSE 0000664 0000000 0000000 00000002053 14306031657 0014111 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) 2021 Zilong Yao
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
js-sdsl-4.1.4/README.md 0000664 0000000 0000000 00000012747 14306031657 0014376 0 ustar 00root root 0000000 0000000
A javascript standard data structure library which benchmark against C++ STL
English | 简体中文
## Included data structures
- Vector
- Stack
- Queue
- LinkList
- Deque
- PriorityQueue
- OrderedSet (using RBTree)
- OrderedMap (using RBTree)
- HashSet
- HashMap
## Benchmark
We are benchmarking against other popular data structure libraries. In some ways we're better than the best library. See [benchmark](https://js-sdsl.github.io/#/test/benchmark-analyze).
## Supported platforms
- node.js (using commonjs)
- react/vue (using es5)
- browser (support most browsers)
## Download
Download directly
- [js-sdsl.js](https://unpkg.com/js-sdsl/dist/umd/js-sdsl.js) (for development)
- [js-sdsl.min.js](https://unpkg.com/js-sdsl/dist/umd/js-sdsl.min.js) (for production)
Or install js-sdsl using npm
```bash
npm install js-sdsl
```
## Usage
You can visit our [official website](https://js-sdsl.github.io/) to get more information.
To help you have a better use, we also provide this [API document](https://js-sdsl.github.io/js-sdsl/index.html).
### For browser
```html
```
### For npm
```javascript
// esModule
import { OrderedMap } from 'js-sdsl';
// commonJs
const { OrderedMap } = require('js-sdsl');
const myOrderedMap = new OrderedMap();
myOrderedMap.setElement(1, 2);
console.log(myOrderedMap.getElementByKey(1)); // 2
```
## Build by source code
You can pull this repository and run `yarn build` to rebuild this library.
## Test
### Unit test
We use jest library to write unit tests, you can see test coverage on [coveralls](https://coveralls.io/github/js-sdsl/js-sdsl). You can run `yarn test:unit` command to reproduce it.
### For performance
We tested most of the functions for efficiency. You can go to [`gh-pages/performance.md`](https://github.com/js-sdsl/js-sdsl/blob/gh-pages/performance.md) to see our running results or reproduce it with `yarn test:performance` command.
You can also visit [here](https://js-sdsl.github.io/#/test/performance-test) to get the result.
## Maintainers
[@ZLY201](https://github.com/ZLY201)
## Contributing
Feel free to dive in! Open an issue or submit PRs. It may be helpful to read the [Contributor Guide](https://github.com/js-sdsl/js-sdsl/blob/main/.github/CONTRIBUTING.md).
### Contributors
Thanks goes to these wonderful people:
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
## License
[MIT](https://github.com/js-sdsl/js-sdsl/blob/main/LICENSE) © ZLY201
js-sdsl-4.1.4/README.zh-CN.md 0000664 0000000 0000000 00000012770 14306031657 0015310 0 ustar 00root root 0000000 0000000
一个参考 C++ STL 实现的 JavaScript 标准数据结构库
English | 简体中文
## 包含的数据结构
- Vector
- Stack
- Queue
- LinkList
- Deque
- PriorityQueue
- OrderedSet (using RBTree)
- OrderedMap (using RBTree)
- HashSet
- HashMap
## Benchmark
我们和其他数据结构库进行了基准测试,在某些场景我们甚至超过了当前最流行的库
查看 [benchmark](https://js-sdsl.github.io/#/zh-cn/test/benchmark-analyze) 以获取更多信息
## 支持的平台
- node.js (using commonjs)
- react/vue (using es5)
- browser (support most browsers)
## 下载
使用 cdn 直接引入
- [js-sdsl.js](https://unpkg.com/js-sdsl/dist/umd/js-sdsl.js) (for development)
- [js-sdsl.min.js](https://unpkg.com/js-sdsl/dist/umd/js-sdsl.min.js) (for production)
使用 npm 下载
```bash
npm install js-sdsl
```
## 使用说明
您可以[访问我们的主页](https://js-sdsl.github.io/)获取更多信息
并且我们提供了完整的 [API 文档](https://js-sdsl.github.io/js-sdsl/index.html)供您参考
### 在浏览器中使用
```html
```
### npm 引入
```javascript
// esModule
import { OrderedMap } from 'js-sdsl';
// commonJs
const { OrderedMap } = require('js-sdsl');
const myOrderedMap = new OrderedMap();
myOrderedMap.setElement(1, 2);
console.log(myOrderedMap.getElementByKey(1)); // 2
```
## 从源码构建
您可以克隆此仓库后运行 `yarn build` 命令重新构建这个库
## 测试
### 单元测试
我们使用 `jest` 库来编写我们的单元测试,并将结果同步到了 [coveralls](https://coveralls.io/github/js-sdsl/js-sdsl) 上,你可以使用 `yarn test:unit` 命令来重建它
### 对于性能的校验
我们对于编写的所有 API 进行了性能测试,并将结果同步到了 [`gh-pages/performance.md`](https://github.com/js-sdsl/js-sdsl/blob/gh-pages/performance.md) 中,你可以通过 `yarn test:performance` 命令来重现它
您也可以访问[我们的网站](https://js-sdsl.github.io/#/zh-cn/test/performance-test)来获取结果
## 维护者
[@ZLY201](https://github.com/ZLY201)
## 贡献
我们欢迎所有的开发人员提交 issue 或 pull request,阅读[贡献者指南](https://github.com/js-sdsl/js-sdsl/blob/main/.github/CONTRIBUTING.md)可能会有所帮助
### 贡献者
感谢对本项目做出贡献的开发者们:
本项目遵循 [all-contributors](https://github.com/all-contributors/all-contributors) 规范。 欢迎任何形式的贡献!
## 许可证
[MIT](https://github.com/js-sdsl/js-sdsl/blob/main/LICENSE) © ZLY201
js-sdsl-4.1.4/jest.config.ts 0000664 0000000 0000000 00000000405 14306031657 0015664 0 ustar 00root root 0000000 0000000 module.exports = {
preset: 'ts-jest',
roots: [
'/test'
],
transform: {
'^.+\\.(t|j)sx?$': 'ts-jest'
},
transformIgnorePatterns: [
'node_modules'
],
moduleNameMapper: {
'@/(.*)$': '/src/$1'
}
};
js-sdsl-4.1.4/package.json 0000664 0000000 0000000 00000006212 14306031657 0015373 0 ustar 00root root 0000000 0000000 {
"name": "js-sdsl",
"version": "4.1.4",
"description": "javascript standard data structure library which benchmark against C++ STL",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
"author": {
"name": "ZLY201",
"email": "951711127@qq.com",
"url": "https://github.com/js-sdsl/js-sdsl"
},
"browserslist": [
"last 2 version",
"> 1%",
"not dead",
"maintained node versions"
],
"sideEffects": false,
"homepage": "https://js-sdsl.github.io",
"scripts": {
"setup": "rm -rf node_modules && yarn install",
"dev": "ttsc --project tsconfig.cjs.json --watch",
"build": "yarn build:esm && yarn build:cjs && yarn build:umd:min",
"build:cjs": "rm -rf dist/cjs && ttsc --project tsconfig.cjs.json",
"build:esm": "rm -rf dist/esm && ttsc --project tsconfig.esm.json",
"build:umd": "rm -rf dist/umd && rollup -c",
"build:umd:min": "yarn build:umd && uglifyjs --compress --mangle --source-map --comments -o dist/umd/js-sdsl.min.js -- dist/umd/js-sdsl.js",
"test": "yarn test:unit && yarn test:performance",
"test:unit": "jest --coverage",
"test:performance": "rm -rf dist/performance && ttsc --project tsconfig.performance.json && node dist/performance/performance/index.js",
"lint": "eslint --fix --color --cache --max-warnings=0 .",
"generate": "typedoc src/index.ts",
"generate:dev": "typedoc src/index.ts --watch",
"prepare": "husky install"
},
"lint-staged": {
"*.{js,ts}": [
"yarn lint"
]
},
"devDependencies": {
"@types/jest": "^28.1.6",
"@types/node": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^5.33.1",
"@typescript-eslint/parser": "^5.33.1",
"all-contributors-cli": "^6.20.0",
"browserslist": "^4.21.3",
"caniuse-lite": "^1.0.30001380",
"commitlint": "^17.0.3",
"conventional-changelog-conventionalcommits": "^5.0.0",
"coveralls": "^3.1.1",
"eslint": "^8.4.1",
"eslint-plugin-compat": "^4.0.2",
"gh-pages": "^3.2.3",
"husky": "^8.0.1",
"jest": "^28.1.3",
"lint-staged": "^12.1.0",
"rollup": "^2.78.1",
"rollup-plugin-typescript2": "^0.33.0",
"ts-jest": "^28.0.7",
"ts-node": "^10.9.1",
"ts-transform-paths": "^2.0.3",
"tsconfig-paths": "^4.0.0",
"tslib": "^2.4.0",
"ttypescript": "^1.5.13",
"typedoc": "^0.23.10",
"typedoc-plugin-missing-exports": "^1.0.0",
"typescript": "^4.7.4",
"uglify-js": "^3.14.5"
},
"repository": {
"type": "github",
"url": "https://github.com/js-sdsl/js-sdsl.git"
},
"license": "MIT",
"files": [
"dist/cjs",
"dist/esm",
"dist/umd",
"CHANGELOG.md"
],
"keywords": [
"data",
"structure",
"data structure",
"rbTree",
"rbtree",
"RBTree",
"red black tree",
"ordered",
"set",
"map",
"ordered map",
"ordered set",
"deque",
"heap",
"priority queue",
"link list",
"LinkList",
"linkedList",
"vector",
"stack",
"queue",
"hash",
"hash set",
"hash map",
"c++",
"stl"
],
"bugs": {
"email": "951711127@qq.com",
"url": "https://github.com/js-sdsl/js-sdsl/issues"
},
"dependencies": {}
}
js-sdsl-4.1.4/performance/ 0000775 0000000 0000000 00000000000 14306031657 0015405 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/performance/HashContainerTest/ 0000775 0000000 0000000 00000000000 14306031657 0020773 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/performance/HashContainerTest/HashMap.performance.ts 0000664 0000000 0000000 00000002554 14306031657 0025172 0 ustar 00root root 0000000 0000000 import { HashMap } from '@/index';
import { testReportFormat } from '../index';
function testHashMap(arr: number[], testNum: number) {
let startTime, endTime;
const reportList: testReportFormat['reportList'] = [];
startTime = Date.now();
const myHashMap = new HashMap(arr.map((element, index) => [index, element]), (1 << 21));
endTime = Date.now();
reportList.push({
testFunc: 'constructor',
testNum: 1,
containerSize: myHashMap.size(),
runTime: endTime - startTime
});
startTime = Date.now();
for (let i = 0; i < testNum; ++i) myHashMap.setElement(i, Math.random() * 1000000);
endTime = Date.now();
reportList.push({
testFunc: 'setElement',
testNum,
containerSize: myHashMap.size(),
runTime: endTime - startTime
});
startTime = Date.now();
myHashMap.forEach(([key]) => myHashMap.getElementByKey(key));
endTime = Date.now();
reportList.push({
testFunc: 'getElementByKey',
testNum: myHashMap.size(),
containerSize: myHashMap.size(),
runTime: endTime - startTime
});
const size = myHashMap.size();
startTime = Date.now();
for (let i = 0; i < testNum; ++i) myHashMap.eraseElementByKey(i);
endTime = Date.now();
reportList.push({
testFunc: 'eraseElementByKey',
testNum,
containerSize: size,
runTime: endTime - startTime
});
return reportList;
}
export default testHashMap;
js-sdsl-4.1.4/performance/HashContainerTest/HashSet.performance.ts 0000664 0000000 0000000 00000002606 14306031657 0025206 0 ustar 00root root 0000000 0000000 import { HashSet } from '@/index';
import { testReportFormat } from '../index';
function testHashSet(arr: number[], testNum: number) {
let startTime, endTime;
const reportList: testReportFormat['reportList'] = [];
startTime = Date.now();
const myHashSet = new HashSet(arr, (1 << 21));
endTime = Date.now();
reportList.push({
testFunc: 'constructor',
testNum: 1,
containerSize: myHashSet.size(),
runTime: endTime - startTime
});
const stdSet = new Set(arr);
startTime = Date.now();
for (let i = 0; i < testNum; ++i) myHashSet.insert(Math.random() * 1000000);
endTime = Date.now();
reportList.push({
testFunc: 'insert',
testNum,
containerSize: myHashSet.size(),
runTime: endTime - startTime
});
startTime = Date.now();
myHashSet.forEach(element => myHashSet.find(element));
endTime = Date.now();
reportList.push({
testFunc: 'find',
testNum: myHashSet.size(),
containerSize: myHashSet.size(),
runTime: endTime - startTime
});
myHashSet.forEach(element => stdSet.add(element));
const size = myHashSet.size();
startTime = Date.now();
stdSet.forEach(element => myHashSet.eraseElementByKey(element));
endTime = Date.now();
reportList.push({
testFunc: 'eraseElementByKey',
testNum: stdSet.size,
containerSize: size,
runTime: endTime - startTime
});
return reportList;
}
export default testHashSet;
js-sdsl-4.1.4/performance/OtherContainerTest/ 0000775 0000000 0000000 00000000000 14306031657 0021171 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/performance/OtherContainerTest/PriorityQueue.performance.ts 0000664 0000000 0000000 00000002077 14306031657 0026675 0 ustar 00root root 0000000 0000000 import { PriorityQueue } from '@/index';
import { testReportFormat } from '../index';
function testPriorityQueue(arr: number[], testNum: number) {
let startTime, endTime;
const reportList: testReportFormat['reportList'] = [];
startTime = Date.now();
const myPriority = new PriorityQueue(arr, (x: number, y: number) => y - x, false);
endTime = Date.now();
reportList.push({
testFunc: 'constructor',
testNum: 1,
containerSize: myPriority.size(),
runTime: endTime - startTime
});
startTime = Date.now();
for (let i = 0; i < testNum; ++i) myPriority.push(Math.random() * 1000000);
endTime = Date.now();
reportList.push({
testFunc: 'push',
testNum,
containerSize: myPriority.size(),
runTime: endTime - startTime
});
startTime = Date.now();
const size = myPriority.size();
while (!myPriority.empty()) myPriority.pop();
endTime = Date.now();
reportList.push({
testFunc: 'pop all',
testNum: 1,
containerSize: size,
runTime: endTime - startTime
});
return reportList;
}
export default testPriorityQueue;
js-sdsl-4.1.4/performance/OtherContainerTest/Queue.performance.ts 0000664 0000000 0000000 00000001366 14306031657 0025133 0 ustar 00root root 0000000 0000000 import { Queue } from '@/index';
import { testReportFormat } from '../index';
function testQueue(arr: number[], testNum: number) {
const myQueue = new Queue(arr);
let startTime, endTime;
const reportList: testReportFormat['reportList'] = [];
startTime = Date.now();
for (let i = 0; i < testNum; ++i) myQueue.push(i);
endTime = Date.now();
reportList.push({
testFunc: 'push',
testNum,
containerSize: myQueue.size(),
runTime: endTime - startTime
});
startTime = Date.now();
const size = myQueue.size();
myQueue.clear();
endTime = Date.now();
reportList.push({
testFunc: 'clear',
testNum: 1,
containerSize: size,
runTime: endTime - startTime
});
return reportList;
}
export default testQueue;
js-sdsl-4.1.4/performance/OtherContainerTest/Stack.performance.ts 0000664 0000000 0000000 00000001426 14306031657 0025111 0 ustar 00root root 0000000 0000000 import { Stack } from '@/index';
import { testReportFormat } from '../index';
function testStack(arr: number[], testNum: number) {
const myStack = new Stack(arr);
let startTime, endTime;
const reportList: testReportFormat['reportList'] = [];
startTime = Date.now();
for (let i = 0; i < testNum; ++i) {
myStack.push(Math.random() * 1000000);
}
endTime = Date.now();
reportList.push({
testFunc: 'push',
testNum,
containerSize: myStack.size(),
runTime: endTime - startTime
});
startTime = Date.now();
const size = myStack.size();
myStack.clear();
endTime = Date.now();
reportList.push({
testFunc: 'clear',
testNum: 1,
containerSize: size,
runTime: endTime - startTime
});
return reportList;
}
export default testStack;
js-sdsl-4.1.4/performance/SequentialContainerTest/ 0000775 0000000 0000000 00000000000 14306031657 0022222 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/performance/SequentialContainerTest/Deque.performance.ts 0000664 0000000 0000000 00000002061 14306031657 0026134 0 ustar 00root root 0000000 0000000 import { Deque } from '@/index';
import testSequentialContainer from './SequentialContainer.performance';
function testDeque(arr: number[], testNum: number) {
const myDeque = new Deque(arr);
const reportList = testSequentialContainer(myDeque, testNum);
let startTime, endTime;
startTime = Date.now();
for (let i = 0; i < testNum * 2; ++i) myDeque.pushFront(i);
endTime = Date.now();
reportList.push({
testFunc: 'pushFront',
testNum: testNum * 2,
containerSize: myDeque.size(),
runTime: endTime - startTime
});
startTime = Date.now();
const size = myDeque.size();
for (let i = 0; i < testNum; ++i) myDeque.popFront();
endTime = Date.now();
reportList.push({
testFunc: 'popFront',
testNum,
containerSize: size,
runTime: endTime - startTime
});
startTime = Date.now();
myDeque.shrinkToFit();
endTime = Date.now();
reportList.push({
testFunc: 'shrinkToFit',
testNum: 1,
containerSize: myDeque.size(),
runTime: endTime - startTime
});
return reportList;
}
export default testDeque;
js-sdsl-4.1.4/performance/SequentialContainerTest/LinkList.performance.ts 0000664 0000000 0000000 00000002670 14306031657 0026630 0 ustar 00root root 0000000 0000000 import { LinkList } from '@/index';
import testSequentialContainer from './SequentialContainer.performance';
function testLinkList(arr: number[], testNum: number) {
const myLinkList = new LinkList(arr);
const reportList = testSequentialContainer(myLinkList, testNum);
const tmpArr = [];
for (let i = 0; i < 10000; ++i) {
tmpArr.push(Math.random() * 1000000);
}
let startTime, endTime;
startTime = Date.now();
for (let i = 0; i < testNum; ++i) myLinkList.pushFront(i);
endTime = Date.now();
reportList.push({
testFunc: 'pushFront',
testNum,
containerSize: myLinkList.size(),
runTime: endTime - startTime
});
startTime = Date.now();
const size = myLinkList.size();
for (let i = 0; i < testNum; ++i) myLinkList.popFront();
endTime = Date.now();
reportList.push({
testFunc: 'popFront',
testNum,
containerSize: size,
runTime: endTime - startTime
});
const _otherLinkList = new LinkList();
for (let i = 0; i < testNum; ++i) _otherLinkList.pushBack(Math.random() * 1000000);
myLinkList.forEach(element => tmpArr.push(element));
myLinkList.sort((x, y) => x - y);
_otherLinkList.sort((x, y) => x - y);
startTime = Date.now();
myLinkList.merge(_otherLinkList);
endTime = Date.now();
reportList.push({
testFunc: 'merge',
testNum: 1,
containerSize: myLinkList.size(),
runTime: endTime - startTime
});
return reportList;
}
export default testLinkList;
js-sdsl-4.1.4/performance/SequentialContainerTest/SequentialContainer.performance.ts 0000664 0000000 0000000 00000007143 14306031657 0031054 0 ustar 00root root 0000000 0000000 import { testReportFormat } from '../index';
import SequentialContainer from '@/container/SequentialContainer/Base/index';
function testSequentialContainer(container: SequentialContainer, testNum: number) {
let startTime, endTime;
const reportList: testReportFormat['reportList'] = [];
let _testNum = testNum;
startTime = Date.now();
for (let i = 0; i < testNum; ++i) container.pushBack(Math.random());
endTime = Date.now();
reportList.push({
testFunc: 'pushBack',
testNum,
containerSize: container.size(),
runTime: endTime - startTime
});
startTime = Date.now();
let size = container.size();
for (let i = 0; i < testNum; ++i) container.popBack();
endTime = Date.now();
reportList.push({
testFunc: 'popBack',
testNum,
containerSize: size,
runTime: endTime - startTime
});
for (let i = 0; i < testNum; ++i) {
container.pushBack(i);
}
if (container.constructor.name === 'LinkList') {
_testNum = Math.min(testNum, 1000);
}
startTime = Date.now();
for (let i = 0; i < _testNum; ++i) {
container.getElementByPos(i);
}
endTime = Date.now();
reportList.push({
testFunc: 'getElementByPos',
testNum: _testNum,
containerSize: container.size(),
runTime: endTime - startTime
});
if (container.constructor.name === 'LinkList') {
_testNum = Math.min(testNum, 1000);
}
startTime = Date.now();
for (let i = 0; i < _testNum; ++i) container.setElementByPos(i, i);
endTime = Date.now();
reportList.push({
testFunc: 'setElementByPos',
testNum: _testNum,
containerSize: container.size(),
runTime: endTime - startTime
});
startTime = Date.now();
size = container.size();
for (let i = 0; i < 50; ++i) {
container.eraseElementByPos(Math.floor(Math.random() * container.size()));
}
endTime = Date.now();
reportList.push({
testFunc: 'eraseElementByPos',
testNum: 50,
containerSize: size,
runTime: endTime - startTime
});
startTime = Date.now();
for (let i = 0; i < 50; ++i) {
container.insert(Math.floor(Math.random() * container.size()), -1, 2);
}
endTime = Date.now();
reportList.push({
testFunc: 'insert',
testNum: 50,
containerSize: container.size(),
runTime: endTime - startTime
});
startTime = Date.now();
size = container.size();
container.eraseElementByValue(-1);
endTime = Date.now();
reportList.push({
testFunc: 'eraseElementByValue',
testNum: 1,
containerSize: size,
runTime: endTime - startTime
});
startTime = Date.now();
container.reverse();
endTime = Date.now();
reportList.push({
testFunc: 'reverse',
testNum: 1,
containerSize: container.size(),
runTime: endTime - startTime
});
for (let i = 0; i < 50; ++i) {
container.insert(Math.floor(Math.random() * container.size()), -1, 2);
}
size = container.size();
startTime = Date.now();
container.unique();
endTime = Date.now();
reportList.push({
testFunc: 'unique',
testNum: 1,
containerSize: size,
runTime: endTime - startTime
});
for (let i = 0; i < testNum; ++i) {
container.pushBack(Math.random() * testNum);
}
startTime = Date.now();
container.sort((x, y) => x - y);
endTime = Date.now();
reportList.push({
testFunc: 'sort',
testNum: 1,
containerSize: container.size(),
runTime: endTime - startTime
});
startTime = Date.now();
size = container.size();
container.clear();
endTime = Date.now();
reportList.push({
testFunc: 'clear',
testNum: 1,
containerSize: size,
runTime: endTime - startTime
});
return reportList;
}
export default testSequentialContainer;
js-sdsl-4.1.4/performance/TreeContainerTest/ 0000775 0000000 0000000 00000000000 14306031657 0021007 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/performance/TreeContainerTest/OrderedMap.performance.ts 0000664 0000000 0000000 00000005716 14306031657 0025712 0 ustar 00root root 0000000 0000000 import { OrderedMap } from '@/index';
import { testReportFormat } from '../index';
function testOrderedMap(arr: number[], testNum: number) {
let startTime, endTime;
const reportList: testReportFormat['reportList'] = [];
startTime = Date.now();
const myMap = new OrderedMap(arr.map((element, index) => [element, index]));
endTime = Date.now();
reportList.push({
testFunc: 'constructor',
testNum: 1,
containerSize: myMap.size(),
runTime: endTime - startTime
});
startTime = Date.now();
for (let i = 0; i < testNum; ++i) myMap.setElement(i, Math.random() * 1000000);
endTime = Date.now();
reportList.push({
testFunc: 'setElement',
testNum,
containerSize: myMap.size(),
runTime: endTime - startTime
});
startTime = Date.now();
let size = myMap.size();
for (let i = 0; i < testNum; ++i) myMap.eraseElementByKey(i);
endTime = Date.now();
reportList.push({
testFunc: 'eraseElementByKey',
testNum,
containerSize: size,
runTime: endTime - startTime
});
startTime = Date.now();
size = myMap.size();
for (let i = testNum; i < testNum + 100; ++i) {
myMap.eraseElementByPos(Math.floor(Math.random() * myMap.size()));
}
endTime = Date.now();
reportList.push({
testFunc: 'eraseElementByPos',
testNum: 100,
containerSize: size,
runTime: endTime - startTime
});
const _otherMap = new OrderedMap();
for (let i = testNum; i < testNum * 2; ++i) _otherMap.setElement(i, Math.random() * 1000000);
startTime = Date.now();
myMap.union(_otherMap);
endTime = Date.now();
reportList.push({
testFunc: 'union',
testNum: 1,
containerSize: myMap.size(),
runTime: endTime - startTime
});
let num = 0;
startTime = Date.now();
for (const pair of myMap) {
++num;
if (num >= testNum) break;
myMap.lowerBound(pair[0]);
}
endTime = Date.now();
reportList.push({
testFunc: 'lowerBound',
testNum,
containerSize: myMap.size(),
runTime: endTime - startTime
});
num = 0;
startTime = Date.now();
for (const pair of myMap) {
++num;
if (num >= testNum) break;
myMap.upperBound(pair[0]);
}
endTime = Date.now();
reportList.push({
testFunc: 'upperBound',
testNum,
containerSize: myMap.size(),
runTime: endTime - startTime
});
num = 0;
startTime = Date.now();
for (const pair of myMap) {
++num;
if (num >= testNum) break;
myMap.reverseLowerBound(pair[0]);
}
endTime = Date.now();
reportList.push({
testFunc: 'reverseLowerBound',
testNum,
containerSize: myMap.size(),
runTime: endTime - startTime
});
num = 0;
startTime = Date.now();
for (const pair of myMap) {
++num;
if (num >= testNum) break;
myMap.reverseUpperBound(pair[0]);
}
endTime = Date.now();
reportList.push({
testFunc: 'reverseUpperBound',
testNum,
containerSize: myMap.size(),
runTime: endTime - startTime
});
return reportList;
}
export default testOrderedMap;
js-sdsl-4.1.4/performance/TreeContainerTest/OrderedSet.performance.ts 0000664 0000000 0000000 00000006271 14306031657 0025725 0 ustar 00root root 0000000 0000000 import { OrderedSet } from '@/index';
import { testReportFormat } from '../index';
function testOrderedSet(arr: number[], testNum: number) {
let startTime, endTime;
const reportList: testReportFormat['reportList'] = [];
startTime = Date.now();
const myOrderedSet = new OrderedSet(arr);
endTime = Date.now();
reportList.push({
testFunc: 'constructor',
testNum: 1,
containerSize: myOrderedSet.size(),
runTime: endTime - startTime
});
startTime = Date.now();
for (let i = 0; i < testNum; ++i) myOrderedSet.insert(i);
endTime = Date.now();
reportList.push({
testFunc: 'insert',
testNum,
containerSize: myOrderedSet.size(),
runTime: endTime - startTime
});
for (let i = 0; i < testNum; ++i) myOrderedSet.insert(Math.random() * 1000000);
const tmpArr: number[] = [];
myOrderedSet.forEach((element: number) => tmpArr.push(element));
startTime = Date.now();
const size = myOrderedSet.size();
for (let i = 0; i < testNum; ++i) myOrderedSet.eraseElementByKey(tmpArr[i]);
endTime = Date.now();
reportList.push({
testFunc: 'eraseElementByKey',
testNum,
containerSize: size,
runTime: endTime - startTime
});
startTime = Date.now();
for (let i = 0; i < 10; ++i) {
myOrderedSet.eraseElementByPos(Math.floor(Math.random() * myOrderedSet.size()));
}
endTime = Date.now();
reportList.push({
testFunc: 'eraseElementByPos',
testNum: 10,
containerSize: size,
runTime: endTime - startTime
});
const _otherOrderedSet = new OrderedSet();
for (let i = 0; i < testNum; ++i) _otherOrderedSet.insert(Math.random() * 1000000);
startTime = Date.now();
myOrderedSet.union(_otherOrderedSet);
endTime = Date.now();
reportList.push({
testFunc: 'union',
testNum: 1,
containerSize: myOrderedSet.size(),
runTime: endTime - startTime
});
let num = 0;
startTime = Date.now();
for (const element of myOrderedSet) {
++num;
if (num >= testNum) break;
myOrderedSet.lowerBound(element);
}
endTime = Date.now();
reportList.push({
testFunc: 'lowerBound',
testNum,
containerSize: myOrderedSet.size(),
runTime: endTime - startTime
});
num = 0;
startTime = Date.now();
for (const element of myOrderedSet) {
++num;
if (num >= testNum) break;
myOrderedSet.upperBound(element);
}
endTime = Date.now();
reportList.push({
testFunc: 'upperBound',
testNum,
containerSize: myOrderedSet.size(),
runTime: endTime - startTime
});
num = 0;
startTime = Date.now();
for (const element of myOrderedSet) {
++num;
if (num >= testNum) break;
myOrderedSet.reverseLowerBound(element);
}
endTime = Date.now();
reportList.push({
testFunc: 'reverseLowerBound',
testNum,
containerSize: myOrderedSet.size(),
runTime: endTime - startTime
});
num = 0;
startTime = Date.now();
for (const element of myOrderedSet) {
++num;
if (num >= testNum) break;
myOrderedSet.reverseUpperBound(element);
}
endTime = Date.now();
reportList.push({
testFunc: 'reverseUpperBound',
testNum,
containerSize: myOrderedSet.size(),
runTime: endTime - startTime
});
return reportList;
}
export default testOrderedSet;
js-sdsl-4.1.4/performance/index.ts 0000664 0000000 0000000 00000005772 14306031657 0017077 0 ustar 00root root 0000000 0000000 import testHashMap from './HashContainerTest/HashMap.performance';
import testHashSet from './HashContainerTest/HashSet.performance';
import testPriorityQueue from './OtherContainerTest/PriorityQueue.performance';
import testQueue from './OtherContainerTest/Queue.performance';
import testStack from './OtherContainerTest/Stack.performance';
import testDeque from './SequentialContainerTest/Deque.performance';
import testLinkList from './SequentialContainerTest/LinkList.performance';
import testOrderedMap from './TreeContainerTest/OrderedMap.performance';
import testOrderedSet from './TreeContainerTest/OrderedSet.performance';
import path from 'path';
import env from './utils/env';
import { writeFileSync } from 'fs';
export type testReportFormat = {
containerName: string,
reportList: {
testFunc: string,
containerSize: number,
testNum: number,
runTime: number
}[];
}
type testFunc = (arr: number[], testNum: number) => testReportFormat['reportList'];
const testNum = 1000000;
const arr: number[] = [];
for (let i = 0; i < testNum; ++i) arr.push(Math.random() * testNum * 2);
const testFuncMap: Record = {
Stack: testStack,
Queue: testQueue,
PriorityQueue: testPriorityQueue,
LinkList: testLinkList,
Deque: testDeque,
OrderedSet: testOrderedSet,
OrderedMap: testOrderedMap,
HashSet: testHashSet,
HashMap: testHashMap
};
function testContainer(containerName: string) {
return {
containerName,
reportList: testFuncMap[containerName]([...arr], testNum)
};
}
function main(taskQueue: string[]) {
const testReport: testReportFormat[] = [];
console.log('Container performance test start...');
for (const containerName in testFuncMap) {
if (taskQueue.length === 0 || taskQueue.includes(containerName)) {
console.log(`${containerName} performance test start...`);
testReport.push(testContainer(containerName));
console.log(`${containerName} performance test end.`);
}
}
console.log('All container performance test end.');
console.clear();
console.log('='.repeat(35), 'Report', '='.repeat(35));
testReport.forEach(report => {
console.log('='.repeat(35), report.containerName, '='.repeat(35));
console.table(report.reportList);
});
console.log('='.repeat(35), 'Report', '='.repeat(35));
console.log('saving result...');
let content = env();
content += '\n## Result\n\n';
const savePath = path.resolve(__dirname, '../performance.md');
content += testReport.map(report => {
const { containerName, reportList } = report;
let str = `### ${containerName}
testFunc |
testNum |
containerSize |
runTime |
`;
for (const json of reportList) {
str += `
${json.testFunc} |
${json.testNum} |
${json.containerSize} |
${json.runTime} |
`;
}
str += '
\n';
return str;
}).join('\n');
writeFileSync(savePath, content);
console.log('saved!');
}
main(process.argv.slice(2));
js-sdsl-4.1.4/performance/utils/ 0000775 0000000 0000000 00000000000 14306031657 0016545 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/performance/utils/env.ts 0000664 0000000 0000000 00000001343 14306031657 0017706 0 ustar 00root root 0000000 0000000 import os from 'os';
export default function () {
const v8Version = process.versions.v8;
const nodeVersion = process.versions.node;
const plat =
`${os.type()} ${os.release()} ${os.arch()}
Node.JS ${nodeVersion}
V8 ${v8Version}`;
const cpus = os.cpus().map(function (cpu) {
return cpu.model;
}).reduce(function (o, model) {
if (!o[model]) o[model] = 0;
o[model]++;
return o;
}, {} as { [key: string]: number });
return `This is Js-sdsl performance test. To get source code you can go to [github](https://github.com/js-sdsl/js-sdsl/tree/main/performance).
## Environment
\`\`\`bash
${plat}
${Object.keys(cpus).map(function (key) {
return key + ' \u00d7 ' + cpus[key];
}).join('\n')}
\`\`\`\n`;
}
js-sdsl-4.1.4/rollup.config.ts 0000664 0000000 0000000 00000000643 14306031657 0016240 0 ustar 00root root 0000000 0000000 import { defineConfig } from 'rollup';
import typescript from 'rollup-plugin-typescript2';
module.exports = defineConfig({
input: 'src/index.ts',
output: [{
file: 'dist/umd/js-sdsl.js',
format: 'umd',
name: 'sdsl'
}],
plugins: [
typescript({
tsconfig: 'tsconfig.esm.json',
tsconfigOverride: {
compilerOptions: {
declaration: false
}
}
})
]
});
js-sdsl-4.1.4/src/ 0000775 0000000 0000000 00000000000 14306031657 0013673 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/container/ 0000775 0000000 0000000 00000000000 14306031657 0015655 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/container/ContainerBase/ 0000775 0000000 0000000 00000000000 14306031657 0020372 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/container/ContainerBase/index.ts 0000664 0000000 0000000 00000007160 14306031657 0022055 0 ustar 00root root 0000000 0000000 export abstract class ContainerIterator {
static readonly NORMAL = false;
static readonly REVERSE = true;
/**
* @description Iterator's type.
*/
readonly iteratorType: boolean;
protected node: unknown;
protected constructor(iteratorType: boolean = ContainerIterator.NORMAL) {
this.iteratorType = iteratorType;
}
/**
* @description Pointers to element.
* @return The value of the pointer's element.
*/
abstract get pointer(): T;
/**
* @description Set pointer's value (some containers are unavailable).
* @param newValue The new value you want to set.
*/
abstract set pointer(newValue: T);
/**
* @description Move `this` iterator to pre.
*/
abstract pre(): this;
/**
* @description Move `this` iterator to next.
*/
abstract next(): this;
/**
* @param obj The other iterator you want to compare.
* @return Boolean about if this equals to obj.
* @example container.find(1).equals(container.end());
*/
abstract equals(obj: ContainerIterator): boolean;
/**
* @description Get a copy of itself.
* We do not guarantee the safety of this function.
* Please ensure that the iterator will not fail.
* @return The copy of self.
*/
abstract copy(): ContainerIterator;
}
export abstract class Base {
/**
* @description Container's size.
* @protected
*/
protected length = 0;
/**
* @return The size of the container.
*/
size() {
return this.length;
}
/**
* @return Boolean about if the container is empty.
*/
empty() {
return this.length === 0;
}
/**
* @description Clear the container.
*/
abstract clear(): void;
}
export abstract class Container extends Base {
/**
* @return Iterator pointing to the beginning element.
*/
abstract begin(): ContainerIterator;
/**
* @return Iterator pointing to the super end like c++.
*/
abstract end(): ContainerIterator;
/**
* @return Iterator pointing to the end element.
*/
abstract rBegin(): ContainerIterator;
/**
* @return Iterator pointing to the super begin like c++.
*/
abstract rEnd(): ContainerIterator;
/**
* @return The first element of the container.
*/
abstract front(): T | undefined;
/**
* @return The last element of the container.
*/
abstract back(): T | undefined;
/**
* @description Iterate over all elements in the container.
* @param callback Callback function like Array.forEach.
*/
abstract forEach(callback: (element: T, index: number) => void): void;
/**
* @param element The element you want to find.
* @return An iterator pointing to the element if found, or super end if not found.
*/
abstract find(element: T): ContainerIterator;
/**
* @description Gets the value of the element at the specified position.
*/
abstract getElementByPos(pos: number): T;
/**
* @description Removes the element at the specified position.
* @param pos The element's position you want to remove.
*/
abstract eraseElementByPos(pos: number): void;
/**
* @description Removes element by iterator and move `iter` to next.
* @param iter The iterator you want to erase.
* @example container.eraseElementByIterator(container.begin());
*/
abstract eraseElementByIterator(
iter: ContainerIterator
): ContainerIterator;
/**
* @description Using for 'for...of' syntax like Array.
*/
abstract [Symbol.iterator](): Generator;
}
export type initContainer = (
{ size: number } |
{ length: number } |
{ size(): number }
) &
{ forEach(callback: (element: T) => void): void; };
js-sdsl-4.1.4/src/container/HashContainer/ 0000775 0000000 0000000 00000000000 14306031657 0020403 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/container/HashContainer/Base/ 0000775 0000000 0000000 00000000000 14306031657 0021255 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/container/HashContainer/Base/index.ts 0000664 0000000 0000000 00000003650 14306031657 0022740 0 ustar 00root root 0000000 0000000 import { Base, Container } from '@/container/ContainerBase/index';
abstract class HashContainer extends Base {
protected static readonly sigma = 0.75;
protected static readonly treeifyThreshold = 8;
protected static readonly untreeifyThreshold = 6;
protected static readonly minTreeifySize = 64;
protected static readonly maxBucketNum: number = (1 << 30);
protected bucketNum: number;
protected initBucketNum: number;
protected hashFunc: (x: K) => number;
protected abstract hashTable: Container[];
protected constructor(
initBucketNum = 16,
hashFunc: (x: K) => number =
(x: K) => {
let str;
if (typeof x !== 'string') {
str = JSON.stringify(x);
} else str = x;
let hashCode = 0;
const strLength = str.length;
for (let i = 0; i < strLength; i++) {
const ch = str.charCodeAt(i);
hashCode = ((hashCode << 5) - hashCode) + ch;
hashCode |= 0;
}
return hashCode >>> 0;
}) {
super();
if (initBucketNum < 16 || (initBucketNum & (initBucketNum - 1)) !== 0) {
throw new RangeError('InitBucketNum range error');
}
this.bucketNum = this.initBucketNum = initBucketNum;
this.hashFunc = hashFunc;
}
clear() {
this.length = 0;
this.bucketNum = this.initBucketNum;
this.hashTable = [];
}
/**
* @description Growth the hash table.
* @protected
*/
protected abstract reAllocate(): void;
abstract forEach(callback: (element: unknown, index: number) => void): void;
/**
* @description Remove the elements of the specified value.
* @param key The element you want to remove.
*/
abstract eraseElementByKey(key: K): void;
/**
* @param key The element you want to find.
* @return Boolean about if the specified element in the hash set.
*/
abstract find(key: K): void;
abstract [Symbol.iterator](): Generator;
}
export default HashContainer;
js-sdsl-4.1.4/src/container/HashContainer/HashMap.ts 0000664 0000000 0000000 00000014576 14306031657 0022311 0 ustar 00root root 0000000 0000000 import HashContainer from './Base/index';
import Vector from '../SequentialContainer/Vector';
import OrderedMap from '../TreeContainer/OrderedMap';
import { initContainer } from '@/container/ContainerBase/index';
class HashMap extends HashContainer {
protected hashTable: (Vector<[K, V]> | OrderedMap)[] = [];
constructor(
container: initContainer<[K, V]> = [],
initBucketNum? :number,
hashFunc?: (x: K) => number) {
super(initBucketNum, hashFunc);
container.forEach(element => this.setElement(element[0], element[1]));
}
protected reAllocate() {
if (this.bucketNum >= HashContainer.maxBucketNum) return;
const newHashTable: (Vector<[K, V]> | OrderedMap)[] = [];
const originalBucketNum = this.bucketNum;
this.bucketNum <<= 1;
const keys = Object.keys(this.hashTable);
const keyNums = keys.length;
for (let i = 0; i < keyNums; ++i) {
const index = parseInt(keys[i]);
const container = this.hashTable[index];
const size = container.size();
if (size === 0) continue;
if (size === 1) {
const element = container.front() as [K, V];
newHashTable[
this.hashFunc(element[0]) & (this.bucketNum - 1)
] = new Vector([element], false);
continue;
}
const lowList: [K, V][] = [];
const highList: [K, V][] = [];
container.forEach(element => {
const hashCode = this.hashFunc(element[0]);
if ((hashCode & originalBucketNum) === 0) {
lowList.push(element);
} else highList.push(element);
});
if (container instanceof OrderedMap) {
if (lowList.length > HashContainer.untreeifyThreshold) {
newHashTable[index] = new OrderedMap(lowList);
} else if (lowList.length) {
newHashTable[index] = new Vector(lowList, false);
}
if (highList.length > HashContainer.untreeifyThreshold) {
newHashTable[index + originalBucketNum] = new OrderedMap(highList);
} else if (highList.length) {
newHashTable[index + originalBucketNum] = new Vector(highList, false);
}
} else {
if (lowList.length >= HashContainer.treeifyThreshold) {
newHashTable[index] = new OrderedMap(lowList);
} else if (lowList.length) {
newHashTable[index] = new Vector(lowList, false);
}
if (highList.length >= HashContainer.treeifyThreshold) {
newHashTable[index + originalBucketNum] = new OrderedMap(highList);
} else if (highList.length) {
newHashTable[index + originalBucketNum] = new Vector(highList, false);
}
}
}
this.hashTable = newHashTable;
}
forEach(callback: (element: [K, V], index: number) => void) {
const containers = Object.values(this.hashTable);
const containersNum = containers.length;
let index = 0;
for (let i = 0; i < containersNum; ++i) {
containers[i].forEach(element => callback(element, index++));
}
}
/**
* @description Insert a new key-value pair to hash map or set value by key.
* @param key The key you want to insert.
* @param value The value you want to insert.
* @example HashMap.setElement(1, 2); // insert a key-value pair [1, 2]
*/
setElement(key: K, value: V) {
const index = this.hashFunc(key) & (this.bucketNum - 1);
const container = this.hashTable[index];
if (!container) {
this.length += 1;
this.hashTable[index] = new Vector([<[K, V]>[key, value]], false);
} else {
const preSize = container.size();
if (container instanceof Vector) {
for (const pair of container) {
if (pair[0] === key) {
pair[1] = value;
return;
}
}
(container as Vector<[K, V]>).pushBack([key, value]);
if (preSize + 1 >= HashMap.treeifyThreshold) {
if (this.bucketNum <= HashMap.minTreeifySize) {
this.length += 1;
this.reAllocate();
return;
}
this.hashTable[index] = new OrderedMap(this.hashTable[index]);
}
this.length += 1;
} else {
(container as OrderedMap).setElement(key, value);
const curSize = container.size();
this.length += curSize - preSize;
}
}
if (this.length > this.bucketNum * HashMap.sigma) {
this.reAllocate();
}
}
/**
* @description Get the value of the element which has the specified key.
* @param key The key you want to get.
*/
getElementByKey(key: K) {
const index = this.hashFunc(key) & (this.bucketNum - 1);
const container = this.hashTable[index];
if (!container) return undefined;
if (container instanceof OrderedMap) {
return (container as OrderedMap).getElementByKey(key);
} else {
for (const pair of container) {
if (pair[0] === key) return pair[1];
}
return undefined;
}
}
eraseElementByKey(key: K) {
const index = this.hashFunc(key) & (this.bucketNum - 1);
const container = this.hashTable[index];
if (!container) return;
if (container instanceof Vector) {
let pos = 0;
for (const pair of container) {
if (pair[0] === key) {
container.eraseElementByPos(pos);
this.length -= 1;
return;
}
pos += 1;
}
} else {
const preSize = container.size();
(container as OrderedMap).eraseElementByKey(key);
const curSize = container.size();
this.length += curSize - preSize;
if (curSize <= HashContainer.untreeifyThreshold) {
this.hashTable[index] = new Vector(container);
}
}
}
find(key: K) {
const index = this.hashFunc(key) & (this.bucketNum - 1);
const container = this.hashTable[index];
if (!container) return false;
if (container instanceof OrderedMap) {
return !(container as OrderedMap).find(key)
.equals((container as OrderedMap).end());
}
for (const pair of container) {
if (pair[0] === key) return true;
}
return false;
}
[Symbol.iterator]() {
return function * (this: HashMap) {
const containers = Object.values(this.hashTable);
const containersNum = containers.length;
for (let i = 0; i < containersNum; ++i) {
const container = containers[i];
for (const element of container) {
yield element;
}
}
}.bind(this)();
}
}
export default HashMap;
js-sdsl-4.1.4/src/container/HashContainer/HashSet.ts 0000664 0000000 0000000 00000012605 14306031657 0022316 0 ustar 00root root 0000000 0000000 import HashContainer from './Base/index';
import Vector from '../SequentialContainer/Vector';
import OrderedSet from '../TreeContainer/OrderedSet';
import { Container, initContainer } from '@/container/ContainerBase/index';
class HashSet extends HashContainer {
protected hashTable: (Vector | OrderedSet)[] = [];
constructor(
container: initContainer = [],
initBucketNum?: number,
hashFunc?: (x: K) => number
) {
super(initBucketNum, hashFunc);
container.forEach(element => this.insert(element));
}
protected reAllocate() {
if (this.bucketNum >= HashContainer.maxBucketNum) return;
const newHashTable: (Vector | OrderedSet)[] = [];
const originalBucketNum = this.bucketNum;
this.bucketNum <<= 1;
const keys = Object.keys(this.hashTable);
const keyNums = keys.length;
for (let i = 0; i < keyNums; ++i) {
const index = parseInt(keys[i]);
const container = this.hashTable[index];
const size = container.size();
if (size === 0) continue;
if (size === 1) {
const element = container.front() as K;
newHashTable[
this.hashFunc(element) & (this.bucketNum - 1)
] = new Vector([element], false);
continue;
}
const lowList: K[] = [];
const highList: K[] = [];
container.forEach(element => {
const hashCode = this.hashFunc(element);
if ((hashCode & originalBucketNum) === 0) {
lowList.push(element);
} else highList.push(element);
});
if (container instanceof OrderedSet) {
if (lowList.length > HashContainer.untreeifyThreshold) {
newHashTable[index] = new OrderedSet(lowList);
} else if (lowList.length) {
newHashTable[index] = new Vector(lowList, false);
}
if (highList.length > HashContainer.untreeifyThreshold) {
newHashTable[index + originalBucketNum] = new OrderedSet(highList);
} else if (highList.length) {
newHashTable[index + originalBucketNum] = new Vector(highList, false);
}
} else {
if (lowList.length >= HashContainer.treeifyThreshold) {
newHashTable[index] = new OrderedSet(lowList);
} else if (lowList.length) {
newHashTable[index] = new Vector(lowList, false);
}
if (highList.length >= HashContainer.treeifyThreshold) {
newHashTable[index + originalBucketNum] = new OrderedSet(highList);
} else if (highList.length) {
newHashTable[index + originalBucketNum] = new Vector(highList, false);
}
}
}
this.hashTable = newHashTable;
}
forEach(callback: (element: K, index: number) => void) {
const containers = Object.values(this.hashTable);
const containersNum = containers.length;
let index = 0;
for (let i = 0; i < containersNum; ++i) {
containers[i].forEach(element => callback(element, index++));
}
}
/**
* @description Insert element to hash set.
* @param element The element you want to insert.
*/
insert(element: K) {
const index = this.hashFunc(element) & (this.bucketNum - 1);
const container = this.hashTable[index];
if (!container) {
this.hashTable[index] = new Vector([element], false);
this.length += 1;
} else {
const preSize = container.size();
if (container instanceof Vector) {
if (!(container as Vector).find(element)
.equals((container as Vector).end())) return;
(container as Vector).pushBack(element);
if (preSize + 1 >= HashContainer.treeifyThreshold) {
if (this.bucketNum <= HashContainer.minTreeifySize) {
this.length += 1;
this.reAllocate();
return;
}
this.hashTable[index] = new OrderedSet(container);
}
this.length += 1;
} else {
(container as OrderedSet).insert(element);
const curSize = container.size();
this.length += curSize - preSize;
}
}
if (this.length > this.bucketNum * HashContainer.sigma) {
this.reAllocate();
}
}
eraseElementByKey(key: K) {
const index = this.hashFunc(key) & (this.bucketNum - 1);
const container = this.hashTable[index];
if (!container) return;
const preSize = container.size();
if (preSize === 0) return;
if (container instanceof Vector) {
(container as Vector).eraseElementByValue(key);
const curSize = container.size();
this.length += curSize - preSize;
} else {
(container as OrderedSet).eraseElementByKey(key);
const curSize = container.size();
this.length += curSize - preSize;
if (curSize <= HashContainer.untreeifyThreshold) {
this.hashTable[index] = new Vector(container);
}
}
}
find(element: K) {
const index = this.hashFunc(element) & (this.bucketNum - 1);
const container = this.hashTable[index];
if (!container) return false;
return !(container as Container).find(element)
.equals((container as Container).end());
}
[Symbol.iterator]() {
return function * (this: HashSet) {
const containers = Object.values(this.hashTable);
const containersNum = containers.length;
for (let i = 0; i < containersNum; ++i) {
const container = containers[i];
for (const element of container) {
yield element;
}
}
}.bind(this)();
}
}
export default HashSet;
js-sdsl-4.1.4/src/container/OtherContainer/ 0000775 0000000 0000000 00000000000 14306031657 0020601 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/container/OtherContainer/PriorityQueue.ts 0000664 0000000 0000000 00000007712 14306031657 0024006 0 ustar 00root root 0000000 0000000 import { Base, initContainer } from '@/container/ContainerBase/index';
class PriorityQueue extends Base {
private readonly priorityQueue: T[];
private readonly cmp: (x: T, y: T) => number;
/**
* @description PriorityQueue's constructor.
* @param container Initialize container, must have a forEach function.
* @param cmp Compare function.
* @param copy When the container is an array, you can choose to directly operate on the original object of
* the array or perform a shallow copy. The default is shallow copy.
*/
constructor(
container: initContainer = [],
cmp: (x: T, y: T) => number =
(x: T, y: T) => {
if (x > y) return -1;
if (x < y) return 1;
return 0;
}, copy = true) {
super();
this.cmp = cmp;
if (Array.isArray(container)) {
this.priorityQueue = copy ? [...container] : container;
} else {
this.priorityQueue = [];
container.forEach(element => this.priorityQueue.push(element));
}
this.length = this.priorityQueue.length;
for (let parent = (this.length - 1) >> 1; parent >= 0; --parent) {
let curParent = parent;
let curChild = (curParent << 1) | 1;
while (curChild < this.length) {
const left = curChild;
const right = left + 1;
let minChild = left;
if (
right < this.length &&
this.cmp(this.priorityQueue[left], this.priorityQueue[right]) > 0
) {
minChild = right;
}
if (this.cmp(this.priorityQueue[curParent], this.priorityQueue[minChild]) <= 0) break;
[this.priorityQueue[curParent], this.priorityQueue[minChild]] =
[this.priorityQueue[minChild], this.priorityQueue[curParent]];
curParent = minChild;
curChild = (curParent << 1) | 1;
}
}
}
/**
* @description Adjusting parent's children to suit the nature of the heap.
* @param parent Parent's index.
* @private
*/
private adjust(parent: number) {
const left = (parent << 1) | 1;
const right = (parent << 1) + 2;
if (
left < this.length &&
this.cmp(this.priorityQueue[parent], this.priorityQueue[left]) > 0
) {
[this.priorityQueue[parent], this.priorityQueue[left]] =
[this.priorityQueue[left], this.priorityQueue[parent]];
}
if (right < this.length &&
this.cmp(this.priorityQueue[parent], this.priorityQueue[right]) > 0
) {
[this.priorityQueue[parent], this.priorityQueue[right]] =
[this.priorityQueue[right], this.priorityQueue[parent]];
}
}
clear() {
this.length = 0;
this.priorityQueue.length = 0;
}
/**
* @description Push element into a container in order.
* @param element The element you want to push.
*/
push(element: T) {
this.priorityQueue.push(element);
this.length += 1;
if (this.length === 1) return;
let curNode = this.length - 1;
while (curNode > 0) {
const parent = (curNode - 1) >> 1;
if (this.cmp(this.priorityQueue[parent], element) <= 0) break;
this.adjust(parent);
curNode = parent;
}
}
/**
* @description Removes the top element.
*/
pop() {
if (!this.length) return;
const last = this.priorityQueue[this.length - 1];
this.length -= 1;
let parent = 0;
while (parent < this.length) {
const left = (parent << 1) | 1;
const right = (parent << 1) + 2;
if (left >= this.length) break;
let minChild = left;
if (
right < this.length &&
this.cmp(this.priorityQueue[left], this.priorityQueue[right]) > 0
) {
minChild = right;
}
if (this.cmp(this.priorityQueue[minChild], last) >= 0) break;
this.priorityQueue[parent] = this.priorityQueue[minChild];
parent = minChild;
}
this.priorityQueue[parent] = last;
this.priorityQueue.pop();
}
/**
* @description Accesses the top element.
*/
top() {
return this.priorityQueue[0] as (T | undefined);
}
}
export default PriorityQueue;
js-sdsl-4.1.4/src/container/OtherContainer/Queue.ts 0000664 0000000 0000000 00000001427 14306031657 0022241 0 ustar 00root root 0000000 0000000 import Deque from '../SequentialContainer/Deque';
import { Base, initContainer } from '@/container/ContainerBase/index';
class Queue extends Base {
private queue: Deque;
constructor(container: initContainer = []) {
super();
this.queue = new Deque(container);
this.length = this.queue.size();
}
clear() {
this.queue.clear();
this.length = 0;
}
/**
* @description Inserts element to queue's end.
*/
push(element: T) {
this.queue.pushBack(element);
this.length += 1;
}
/**
* @description Removes the first element.
*/
pop() {
this.queue.popFront();
if (this.length) this.length -= 1;
}
/**
* @description Access the first element.
*/
front() {
return this.queue.front();
}
}
export default Queue;
js-sdsl-4.1.4/src/container/OtherContainer/Stack.ts 0000664 0000000 0000000 00000001344 14306031657 0022220 0 ustar 00root root 0000000 0000000 import { Base, initContainer } from '@/container/ContainerBase/index';
class Stack extends Base {
private stack: T[] = [];
constructor(container: initContainer = []) {
super();
container.forEach(element => this.push(element));
}
clear() {
this.length = 0;
this.stack.length = 0;
}
/**
* @description Insert element to stack's end.
*/
push(element: T) {
this.stack.push(element);
this.length += 1;
}
/**
* @description Removes the end element.
*/
pop() {
this.stack.pop();
if (this.length > 0) this.length -= 1;
}
/**
* @description Accesses the end element.
*/
top() {
return this.stack[this.length - 1] as (T | undefined);
}
}
export default Stack;
js-sdsl-4.1.4/src/container/SequentialContainer/ 0000775 0000000 0000000 00000000000 14306031657 0021632 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/container/SequentialContainer/Base/ 0000775 0000000 0000000 00000000000 14306031657 0022504 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/container/SequentialContainer/Base/RandomIterator.ts 0000664 0000000 0000000 00000003721 14306031657 0026011 0 ustar 00root root 0000000 0000000 import { checkWithinAccessParams } from '@/utils/checkParams';
import { ContainerIterator } from '@/container/ContainerBase/index';
export abstract class RandomIterator extends ContainerIterator {
protected node: number;
protected readonly size: () => number;
protected readonly getElementByPos: (pos: number) => T;
protected readonly setElementByPos: (pos: number, element: T) => void;
pre: () => this;
next: () => this;
constructor(
index: number,
size: () => number,
getElementByPos: (pos: number) => T,
setElementByPos: (pos: number, element: T) => void,
iteratorType?: boolean
) {
super(iteratorType);
this.node = index;
this.size = size;
this.getElementByPos = getElementByPos;
this.setElementByPos = setElementByPos;
if (this.iteratorType === ContainerIterator.NORMAL) {
this.pre = function () {
if (this.node === 0) {
throw new RangeError('Deque iterator access denied!');
}
this.node -= 1;
return this;
};
this.next = function () {
if (this.node === this.size()) {
throw new RangeError('Deque Iterator access denied!');
}
this.node += 1;
return this;
};
} else {
this.pre = function () {
if (this.node === this.size() - 1) {
throw new RangeError('Deque iterator access denied!');
}
this.node += 1;
return this;
};
this.next = function () {
if (this.node === -1) {
throw new RangeError('Deque iterator access denied!');
}
this.node -= 1;
return this;
};
}
}
get pointer() {
checkWithinAccessParams(this.node, 0, this.size() - 1);
return this.getElementByPos(this.node);
}
set pointer(newValue: T) {
checkWithinAccessParams(this.node, 0, this.size() - 1);
this.setElementByPos(this.node, newValue);
}
equals(obj: RandomIterator) {
return this.node === obj.node;
}
}
js-sdsl-4.1.4/src/container/SequentialContainer/Base/index.ts 0000664 0000000 0000000 00000002643 14306031657 0024170 0 ustar 00root root 0000000 0000000 import { Container } from '@/container/ContainerBase/index';
abstract class SequentialContainer extends Container {
/**
* @description Push the element to the back.
* @param element The element you want to push.
*/
abstract pushBack(element: T): void;
/**
* @description Removes the last element.
*/
abstract popBack(): void;
/**
* @description Sets element by position.
* @param pos The position you want to change.
* @param element The element's value you want to update.
*/
abstract setElementByPos(pos: number, element: T): void;
/**
* @description Removes the elements of the specified value.
* @param value The value you want to remove.
*/
abstract eraseElementByValue(value: T): void;
/**
* @description Insert several elements after the specified position.
* @param pos The position you want to insert.
* @param element The element you want to insert.
* @param num The number of elements you want to insert (default 1).
*/
abstract insert(pos: number, element: T, num?: number): void;
/**
* @description Reverses the container.
*/
abstract reverse(): void;
/**
* @description Removes the duplication of elements in the container.
*/
abstract unique(): void;
/**
* @description Sort the container.
* @param cmp Comparison function.
*/
abstract sort(cmp?: (x: T, y: T) => number): void;
}
export default SequentialContainer;
js-sdsl-4.1.4/src/container/SequentialContainer/Deque.ts 0000664 0000000 0000000 00000025060 14306031657 0023250 0 ustar 00root root 0000000 0000000 import SequentialContainer from './Base/index';
import { checkWithinAccessParams } from '@/utils/checkParams';
import { ContainerIterator, initContainer } from '@/container/ContainerBase/index';
import { RandomIterator } from '@/container/SequentialContainer/Base/RandomIterator';
export class DequeIterator extends RandomIterator {
copy() {
return new DequeIterator(
this.node,
this.size,
this.getElementByPos,
this.setElementByPos,
this.iteratorType
);
}
}
class Deque extends SequentialContainer {
private first = 0;
private curFirst = 0;
private last = 0;
private curLast = 0;
private bucketNum = 0;
private readonly bucketSize: number;
private map: (T | undefined)[][] = [];
constructor(container: initContainer = [], bucketSize = (1 << 12)) {
super();
let _length;
if ('size' in container) {
if (typeof container.size === 'number') {
_length = container.size;
} else {
_length = container.size();
}
} else if ('length' in container) {
_length = container.length;
} else {
throw new RangeError('Can\'t get container\'s size!');
}
this.bucketSize = bucketSize;
this.bucketNum = Math.max(Math.ceil(_length / this.bucketSize), 1);
for (let i = 0; i < this.bucketNum; ++i) {
this.map.push(new Array(this.bucketSize));
}
const needBucketNum = Math.ceil(_length / this.bucketSize);
this.first = this.last = (this.bucketNum >> 1) - (needBucketNum >> 1);
this.curFirst = this.curLast = (this.bucketSize - _length % this.bucketSize) >> 1;
container.forEach(element => this.pushBack(element));
this.size = this.size.bind(this);
this.getElementByPos = this.getElementByPos.bind(this);
this.setElementByPos = this.setElementByPos.bind(this);
}
/**
* @description Growth the Deque.
* @private
*/
private reAllocate() {
const newMap = [];
const addBucketNum = Math.max(this.bucketNum >> 1, 1);
for (let i = 0; i < addBucketNum; ++i) {
newMap[i] = new Array(this.bucketSize);
}
for (let i = this.first; i < this.bucketNum; ++i) {
newMap[newMap.length] = this.map[i];
}
for (let i = 0; i < this.last; ++i) {
newMap[newMap.length] = this.map[i];
}
newMap[newMap.length] = [...this.map[this.last]];
this.first = addBucketNum;
this.last = newMap.length - 1;
for (let i = 0; i < addBucketNum; ++i) {
newMap[newMap.length] = new Array(this.bucketSize);
}
this.map = newMap;
this.bucketNum = newMap.length;
}
/**
* @description Get the bucket position of the element and the pointer position by index.
* @param pos The element's index.
* @private
*/
private getElementIndex(pos: number) {
const offset = this.curFirst + pos + 1;
const offsetRemainder = offset % this.bucketSize;
let curNodePointerIndex = offsetRemainder - 1;
let curNodeBucketIndex = this.first + (offset - offsetRemainder) / this.bucketSize;
if (offsetRemainder === 0) curNodeBucketIndex -= 1;
curNodeBucketIndex %= this.bucketNum;
if (curNodePointerIndex < 0) curNodePointerIndex += this.bucketSize;
return { curNodeBucketIndex, curNodePointerIndex };
}
clear() {
this.map = [[]];
this.bucketNum = 1;
this.first = this.last = this.length = 0;
this.curFirst = this.curLast = this.bucketSize >> 1;
}
front() {
return this.map[this.first][this.curFirst];
}
back() {
return this.map[this.last][this.curLast];
}
begin() {
return new DequeIterator(
0,
this.size,
this.getElementByPos,
this.setElementByPos
);
}
end() {
return new DequeIterator(
this.length,
this.size,
this.getElementByPos,
this.setElementByPos
);
}
rBegin() {
return new DequeIterator(
this.length - 1,
this.size,
this.getElementByPos,
this.setElementByPos,
ContainerIterator.REVERSE
);
}
rEnd() {
return new DequeIterator(
-1,
this.size,
this.getElementByPos,
this.setElementByPos,
ContainerIterator.REVERSE
);
}
pushBack(element: T) {
if (this.length) {
if (this.curLast < this.bucketSize - 1) {
this.curLast += 1;
} else if (this.last < this.bucketNum - 1) {
this.last += 1;
this.curLast = 0;
} else {
this.last = 0;
this.curLast = 0;
}
if (
this.last === this.first &&
this.curLast === this.curFirst
) this.reAllocate();
}
this.length += 1;
this.map[this.last][this.curLast] = element;
}
popBack() {
if (!this.length) return;
this.map[this.last][this.curLast] = undefined;
if (this.length !== 1) {
if (this.curLast > 0) {
this.curLast -= 1;
} else if (this.last > 0) {
this.last -= 1;
this.curLast = this.bucketSize - 1;
} else {
this.last = this.bucketNum - 1;
this.curLast = this.bucketSize - 1;
}
}
this.length -= 1;
}
/**
* @description Push the element to the front.
* @param element The element you want to push.
*/
pushFront(element: T) {
if (this.length) {
if (this.curFirst > 0) {
this.curFirst -= 1;
} else if (this.first > 0) {
this.first -= 1;
this.curFirst = this.bucketSize - 1;
} else {
this.first = this.bucketNum - 1;
this.curFirst = this.bucketSize - 1;
}
if (
this.first === this.last &&
this.curFirst === this.curLast
) this.reAllocate();
}
this.length += 1;
this.map[this.first][this.curFirst] = element;
}
/**
* @description Remove the first element.
*/
popFront() {
if (!this.length) return;
this.map[this.first][this.curFirst] = undefined;
if (this.length !== 1) {
if (this.curFirst < this.bucketSize - 1) {
this.curFirst += 1;
} else if (this.first < this.bucketNum - 1) {
this.first += 1;
this.curFirst = 0;
} else {
this.first = 0;
this.curFirst = 0;
}
}
this.length -= 1;
}
forEach(callback: (element: T, index: number) => void) {
for (let i = 0; i < this.length; ++i) {
callback(this.getElementByPos(i), i);
}
}
getElementByPos(pos: number) {
checkWithinAccessParams(pos, 0, this.length - 1);
const {
curNodeBucketIndex,
curNodePointerIndex
} = this.getElementIndex(pos);
return this.map[curNodeBucketIndex][curNodePointerIndex] as T;
}
setElementByPos(pos: number, element: T) {
checkWithinAccessParams(pos, 0, this.length - 1);
const {
curNodeBucketIndex,
curNodePointerIndex
} = this.getElementIndex(pos);
this.map[curNodeBucketIndex][curNodePointerIndex] = element;
}
insert(pos: number, element: T, num = 1) {
checkWithinAccessParams(pos, 0, this.length);
if (pos === 0) {
while (num--) this.pushFront(element);
} else if (pos === this.length) {
while (num--) this.pushBack(element);
} else {
const arr: T[] = [];
for (let i = pos; i < this.length; ++i) {
arr.push(this.getElementByPos(i));
}
this.cut(pos - 1);
for (let i = 0; i < num; ++i) this.pushBack(element);
for (let i = 0; i < arr.length; ++i) this.pushBack(arr[i]);
}
}
/**
* @description Remove all elements after the specified position (excluding the specified position).
* @param pos The previous position of the first removed element.
* @example deque.cut(1); // Then deque's size will be 2. deque -> [0, 1]
*/
cut(pos: number) {
if (pos < 0) {
this.clear();
return;
}
const {
curNodeBucketIndex,
curNodePointerIndex
} = this.getElementIndex(pos);
this.last = curNodeBucketIndex;
this.curLast = curNodePointerIndex;
this.length = pos + 1;
}
eraseElementByPos(pos: number) {
checkWithinAccessParams(pos, 0, this.length - 1);
if (pos === 0) this.popFront();
else if (pos === this.length - 1) this.popBack();
else {
const arr = [];
for (let i = pos + 1; i < this.length; ++i) {
arr.push(this.getElementByPos(i));
}
this.cut(pos);
this.popBack();
arr.forEach(element => this.pushBack(element));
}
}
eraseElementByValue(value: T) {
if (!this.length) return;
const arr: T[] = [];
for (let i = 0; i < this.length; ++i) {
const element = this.getElementByPos(i);
if (element !== value) arr.push(element);
}
const _length = arr.length;
for (let i = 0; i < _length; ++i) this.setElementByPos(i, arr[i]);
this.cut(_length - 1);
}
eraseElementByIterator(iter: DequeIterator) {
// @ts-ignore
const node = iter.node;
this.eraseElementByPos(node);
iter = iter.next();
return iter;
}
find(element: T) {
for (let i = 0; i < this.length; ++i) {
if (this.getElementByPos(i) === element) {
return new DequeIterator(
i,
this.size,
this.getElementByPos,
this.setElementByPos
);
}
}
return this.end();
}
reverse() {
let l = 0; let r = this.length - 1;
while (l < r) {
const tmp = this.getElementByPos(l);
this.setElementByPos(l, this.getElementByPos(r));
this.setElementByPos(r, tmp);
l += 1;
r -= 1;
}
}
unique() {
if (this.length <= 1) return;
let index = 1;
let pre = this.getElementByPos(0);
for (let i = 1; i < this.length; ++i) {
const cur = this.getElementByPos(i);
if (cur !== pre) {
pre = cur;
this.setElementByPos(index++, cur);
}
}
while (this.length > index) this.popBack();
}
sort(cmp?: (x: T, y: T) => number) {
const arr: T[] = [];
for (let i = 0; i < this.length; ++i) {
arr.push(this.getElementByPos(i));
}
arr.sort(cmp);
for (let i = 0; i < this.length; ++i) this.setElementByPos(i, arr[i]);
}
/**
* @description Remove as much useless space as possible.
*/
shrinkToFit() {
if (!this.length) return;
const arr: T[] = [];
this.forEach(element => arr.push(element));
this.bucketNum = Math.max(Math.ceil(this.length / this.bucketSize), 1);
this.length = this.first = this.last = this.curFirst = this.curLast = 0;
this.map = [];
for (let i = 0; i < this.bucketNum; ++i) {
this.map.push(new Array(this.bucketSize));
}
for (let i = 0; i < arr.length; ++i) this.pushBack(arr[i]);
}
[Symbol.iterator]() {
return function * (this: Deque) {
for (let i = 0; i < this.length; ++i) {
yield this.getElementByPos(i);
}
}.bind(this)();
}
}
export default Deque;
js-sdsl-4.1.4/src/container/SequentialContainer/LinkList.ts 0000664 0000000 0000000 00000024657 14306031657 0023751 0 ustar 00root root 0000000 0000000 import SequentialContainer from './Base/index';
import { checkWithinAccessParams } from '@/utils/checkParams';
import { ContainerIterator, initContainer } from '@/container/ContainerBase/index';
export class LinkNode {
value: T | undefined = undefined;
pre: LinkNode | undefined = undefined;
next: LinkNode | undefined = undefined;
constructor(element?: T) {
this.value = element;
}
}
export class LinkListIterator extends ContainerIterator {
protected node: LinkNode;
private readonly header: LinkNode;
pre: () => this;
next: () => this;
constructor(
node: LinkNode,
header: LinkNode,
iteratorType?: boolean
) {
super(iteratorType);
this.node = node;
this.header = header;
if (this.iteratorType === ContainerIterator.NORMAL) {
this.pre = function () {
if (this.node.pre === this.header) {
throw new RangeError('LinkList iterator access denied!');
}
this.node = this.node.pre as LinkNode;
return this;
};
this.next = function () {
if (this.node === this.header) {
throw new RangeError('LinkList iterator access denied!');
}
this.node = this.node.next as LinkNode;
return this;
};
} else {
this.pre = function () {
if (this.node.next === this.header) {
throw new RangeError('LinkList iterator access denied!');
}
this.node = this.node.next as LinkNode;
return this;
};
this.next = function () {
if (this.node === this.header) {
throw new RangeError('LinkList iterator access denied!');
}
this.node = this.node.pre as LinkNode;
return this;
};
}
}
get pointer() {
if (this.node === this.header) {
throw new RangeError('LinkList iterator access denied!');
}
return this.node.value as T;
}
set pointer(newValue: T) {
if (this.node === this.header) {
throw new RangeError('LinkList iterator access denied!');
}
this.node.value = newValue;
}
equals(obj: LinkListIterator) {
return this.node === obj.node;
}
copy() {
return new LinkListIterator(
this.node,
this.header,
this.iteratorType
);
}
}
class LinkList extends SequentialContainer {
private header: LinkNode = new LinkNode();
private head: LinkNode | undefined = undefined;
private tail: LinkNode | undefined = undefined;
constructor(container: initContainer = []) {
super();
container.forEach(element => this.pushBack(element));
}
clear() {
this.length = 0;
this.head = this.tail = undefined;
this.header.pre = this.header.next = undefined;
}
begin() {
return new LinkListIterator(this.head || this.header, this.header);
}
end() {
return new LinkListIterator(this.header, this.header);
}
rBegin() {
return new LinkListIterator(this.tail || this.header, this.header, ContainerIterator.REVERSE);
}
rEnd() {
return new LinkListIterator(this.header, this.header, ContainerIterator.REVERSE);
}
front() {
return this.head ? this.head.value : undefined;
}
back() {
return this.tail ? this.tail.value : undefined;
}
forEach(callback: (element: T, index: number) => void) {
if (!this.length) return;
let curNode = this.head as LinkNode;
let index = 0;
while (curNode !== this.header) {
callback(curNode.value as T, index++);
curNode = curNode.next as LinkNode;
}
}
getElementByPos(pos: number) {
checkWithinAccessParams(pos, 0, this.length - 1);
let curNode = this.head as LinkNode;
while (pos--) {
curNode = curNode.next as LinkNode;
}
return curNode.value as T;
}
eraseElementByPos(pos: number) {
checkWithinAccessParams(pos, 0, this.length - 1);
if (pos === 0) this.popFront();
else if (pos === this.length - 1) this.popBack();
else {
let curNode = this.head;
while (pos--) {
curNode = (curNode as LinkNode).next;
}
curNode = curNode as LinkNode;
const pre = curNode.pre as LinkNode;
const next = curNode.next as LinkNode;
next.pre = pre;
pre.next = next;
this.length -= 1;
}
}
eraseElementByValue(value: T) {
while (this.head && this.head.value === value) this.popFront();
while (this.tail && this.tail.value === value) this.popBack();
if (!this.head) return;
let curNode: LinkNode = this.head;
while (curNode !== this.header) {
if (curNode.value === value) {
const pre = curNode.pre;
const next = curNode.next;
if (next) next.pre = pre;
if (pre) pre.next = next;
this.length -= 1;
}
curNode = curNode.next as LinkNode;
}
}
eraseElementByIterator(iter: LinkListIterator) {
// @ts-ignore
const node = iter.node;
if (node === this.header) {
throw new RangeError('Invalid iterator');
}
iter = iter.next();
if (this.head === node) this.popFront();
else if (this.tail === node) this.popBack();
else {
const pre = node.pre;
const next = node.next;
if (next) next.pre = pre;
if (pre) pre.next = next;
this.length -= 1;
}
return iter;
}
pushBack(element: T) {
this.length += 1;
const newTail = new LinkNode(element);
if (!this.tail) {
this.head = this.tail = newTail;
this.header.next = this.head;
this.head.pre = this.header;
} else {
this.tail.next = newTail;
newTail.pre = this.tail;
this.tail = newTail;
}
this.tail.next = this.header;
this.header.pre = this.tail;
}
popBack() {
if (!this.tail) return;
this.length -= 1;
if (this.head === this.tail) {
this.head = this.tail = undefined;
this.header.next = undefined;
} else {
this.tail = this.tail.pre;
if (this.tail) this.tail.next = undefined;
}
this.header.pre = this.tail;
if (this.tail) this.tail.next = this.header;
}
setElementByPos(pos: number, element: T) {
checkWithinAccessParams(pos, 0, this.length - 1);
let curNode = this.head as LinkNode;
while (pos--) {
curNode = curNode.next as LinkNode;
}
curNode.value = element;
}
insert(pos: number, element: T, num = 1) {
checkWithinAccessParams(pos, 0, this.length);
if (num <= 0) return;
if (pos === 0) {
while (num--) this.pushFront(element);
} else if (pos === this.length) {
while (num--) this.pushBack(element);
} else {
let curNode = this.head as LinkNode;
for (let i = 1; i < pos; ++i) {
curNode = curNode.next as LinkNode;
}
const next = curNode.next;
this.length += num;
while (num--) {
curNode.next = new LinkNode(element);
curNode.next.pre = curNode;
curNode = curNode.next;
}
curNode.next = next;
if (next) next.pre = curNode;
}
}
find(element: T) {
if (!this.head) return this.end();
let curNode = this.head;
while (curNode !== this.header) {
if (curNode.value === element) {
return new LinkListIterator(curNode, this.header);
}
curNode = curNode.next as LinkNode;
}
return this.end();
}
reverse() {
if (this.length <= 1) return;
let pHead = this.head as LinkNode;
let pTail = this.tail as LinkNode;
let cnt = 0;
while ((cnt << 1) < this.length) {
const tmp = pHead.value;
pHead.value = pTail.value;
pTail.value = tmp;
pHead = pHead.next as LinkNode;
pTail = pTail.pre as LinkNode;
cnt += 1;
}
}
unique() {
if (this.length <= 1) return;
let curNode = this.head as LinkNode;
while (curNode !== this.header) {
let tmpNode = curNode;
while (tmpNode.next && tmpNode.value === tmpNode.next.value) {
tmpNode = tmpNode.next;
this.length -= 1;
}
curNode.next = tmpNode.next;
if (curNode.next) curNode.next.pre = curNode;
curNode = curNode.next as LinkNode;
}
}
sort(cmp?: (x: T, y: T) => number) {
if (this.length <= 1) return;
const arr: T[] = [];
this.forEach(element => arr.push(element));
arr.sort(cmp);
let curNode: LinkNode = this.head as LinkNode;
arr.forEach((element) => {
curNode.value = element;
curNode = curNode.next as LinkNode;
});
}
/**
* @description Push an element to the front.
* @param element The element you want to push.
*/
pushFront(element: T) {
this.length += 1;
const newHead = new LinkNode(element);
if (!this.head) {
this.head = this.tail = newHead;
this.tail.next = this.header;
this.header.pre = this.tail;
} else {
newHead.next = this.head;
this.head.pre = newHead;
this.head = newHead;
}
this.header.next = this.head;
this.head.pre = this.header;
}
/**
* @description Removes the first element.
*/
popFront() {
if (!this.head) return;
this.length -= 1;
if (this.head === this.tail) {
this.head = this.tail = undefined;
this.header.pre = this.tail;
} else {
this.head = this.head.next;
if (this.head) this.head.pre = this.header;
}
this.header.next = this.head;
}
/**
* @description Merges two sorted lists.
* @param list The other list you want to merge (must be sorted).
*/
merge(list: LinkList) {
if (!this.head) {
list.forEach(element => this.pushBack(element));
return;
}
let curNode: LinkNode = this.head;
list.forEach(element => {
while (
curNode &&
curNode !== this.header &&
(curNode.value as T) <= element
) {
curNode = curNode.next as LinkNode;
}
if (curNode === this.header) {
this.pushBack(element);
curNode = this.tail as LinkNode;
} else if (curNode === this.head) {
this.pushFront(element);
curNode = this.head;
} else {
this.length += 1;
const pre = curNode.pre as LinkNode;
pre.next = new LinkNode(element);
pre.next.pre = pre;
pre.next.next = curNode;
curNode.pre = pre.next;
}
});
}
[Symbol.iterator]() {
return function * (this: LinkList) {
if (!this.head) return;
let curNode = this.head;
while (curNode !== this.header) {
yield curNode.value as T;
curNode = curNode.next as LinkNode;
}
}.bind(this)();
}
}
export default LinkList;
js-sdsl-4.1.4/src/container/SequentialContainer/Vector.ts 0000664 0000000 0000000 00000010367 14306031657 0023453 0 ustar 00root root 0000000 0000000 import SequentialContainer from './Base/index';
import { checkWithinAccessParams } from '@/utils/checkParams';
import { ContainerIterator, initContainer } from '@/container/ContainerBase/index';
import { RandomIterator } from '@/container/SequentialContainer/Base/RandomIterator';
export class VectorIterator extends RandomIterator {
copy() {
return new VectorIterator(
this.node,
this.size,
this.getElementByPos,
this.setElementByPos,
this.iteratorType
);
}
}
class Vector extends SequentialContainer {
private readonly vector: T[];
/**
* @description Vector's constructor.
* @param container Initialize container, must have a forEach function.
* @param copy When the container is an array, you can choose to directly operate on the original object of
* the array or perform a shallow copy. The default is shallow copy.
*/
constructor(container: initContainer = [], copy = true) {
super();
if (Array.isArray(container)) {
this.vector = copy ? [...container] : container;
this.length = container.length;
} else {
this.vector = [];
container.forEach(element => this.pushBack(element));
}
this.size = this.size.bind(this);
this.getElementByPos = this.getElementByPos.bind(this);
this.setElementByPos = this.setElementByPos.bind(this);
}
clear() {
this.length = 0;
this.vector.length = 0;
}
begin() {
return new VectorIterator(
0,
this.size,
this.getElementByPos,
this.setElementByPos
);
}
end() {
return new VectorIterator(
this.length,
this.size,
this.getElementByPos,
this.setElementByPos
);
}
rBegin() {
return new VectorIterator(
this.length - 1,
this.size,
this.getElementByPos,
this.setElementByPos,
ContainerIterator.REVERSE
);
}
rEnd() {
return new VectorIterator(
-1,
this.size,
this.getElementByPos,
this.setElementByPos,
ContainerIterator.REVERSE
);
}
front() {
return this.vector[0] as (T | undefined);
}
back() {
return this.vector[this.length - 1] as (T | undefined);
}
forEach(callback: (element: T, index: number) => void) {
for (let i = 0; i < this.length; ++i) {
callback(this.vector[i], i);
}
}
getElementByPos(pos: number) {
checkWithinAccessParams(pos, 0, this.length - 1);
return this.vector[pos];
}
eraseElementByPos(pos: number) {
checkWithinAccessParams(pos, 0, this.length - 1);
this.vector.splice(pos, 1);
this.length -= 1;
}
eraseElementByValue(value: T) {
let index = 0;
for (let i = 0; i < this.length; ++i) {
if (this.vector[i] !== value) {
this.vector[index++] = this.vector[i];
}
}
this.length = this.vector.length = index;
}
eraseElementByIterator(iter: VectorIterator) {
// @ts-ignore
const node = iter.node;
iter = iter.next();
this.eraseElementByPos(node);
return iter;
}
pushBack(element: T) {
this.vector.push(element);
this.length += 1;
}
popBack() {
if (!this.length) return;
this.vector.pop();
this.length -= 1;
}
setElementByPos(pos: number, element: T) {
checkWithinAccessParams(pos, 0, this.length - 1);
this.vector[pos] = element;
}
insert(pos: number, element: T, num = 1) {
checkWithinAccessParams(pos, 0, this.length);
this.vector.splice(pos, 0, ...new Array(num).fill(element));
this.length += num;
}
find(element: T) {
for (let i = 0; i < this.length; ++i) {
if (this.vector[i] === element) {
return new VectorIterator(
i,
this.size,
this.getElementByPos,
this.getElementByPos
);
}
}
return this.end();
}
reverse() {
this.vector.reverse();
}
unique() {
let index = 1;
for (let i = 1; i < this.length; ++i) {
if (this.vector[i] !== this.vector[i - 1]) {
this.vector[index++] = this.vector[i];
}
}
this.length = this.vector.length = index;
}
sort(cmp?: (x: T, y: T) => number) {
this.vector.sort(cmp);
}
[Symbol.iterator]() {
return function * (this: Vector) {
return yield * this.vector;
}.bind(this)();
}
}
export default Vector;
js-sdsl-4.1.4/src/container/TreeContainer/ 0000775 0000000 0000000 00000000000 14306031657 0020417 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/container/TreeContainer/Base/ 0000775 0000000 0000000 00000000000 14306031657 0021271 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/container/TreeContainer/Base/TreeIterator.ts 0000664 0000000 0000000 00000003001 14306031657 0024244 0 ustar 00root root 0000000 0000000 import TreeNode from './TreeNode';
import { ContainerIterator } from '@/container/ContainerBase/index';
abstract class TreeIterator extends ContainerIterator {
protected node: TreeNode;
protected header: TreeNode;
pre: () => this;
next: () => this;
constructor(
node: TreeNode,
header: TreeNode,
iteratorType?: boolean
) {
super(iteratorType);
this.node = node;
this.header = header;
if (this.iteratorType === ContainerIterator.NORMAL) {
this.pre = function () {
if (this.node === this.header.left) {
throw new RangeError('LinkList iterator access denied!');
}
this.node = this.node.pre();
return this;
};
this.next = function () {
if (this.node === this.header) {
throw new RangeError('LinkList iterator access denied!');
}
this.node = this.node.next();
return this;
};
} else {
this.pre = function () {
if (this.node === this.header.right) {
throw new RangeError('LinkList iterator access denied!');
}
this.node = this.node.next();
return this;
};
this.next = function () {
if (this.node === this.header) {
throw new RangeError('LinkList iterator access denied!');
}
this.node = this.node.pre();
return this;
};
}
}
equals(obj: TreeIterator) {
return this.node === obj.node;
}
}
export default TreeIterator;
js-sdsl-4.1.4/src/container/TreeContainer/Base/TreeNode.ts 0000664 0000000 0000000 00000005422 14306031657 0023351 0 ustar 00root root 0000000 0000000 class TreeNode {
static readonly RED = true;
static readonly BLACK = false;
color = true;
key: K | undefined = undefined;
value: V | undefined = undefined;
left: TreeNode | undefined = undefined;
right: TreeNode | undefined = undefined;
parent: TreeNode | undefined = undefined;
constructor(key?: K, value?: V) {
this.key = key;
this.value = value;
}
/**
* @description Get the pre node.
* @return TreeNode about the pre node.
*/
pre() {
let preNode: TreeNode = this;
if (
preNode.color === TreeNode.RED &&
(preNode.parent as TreeNode).parent === preNode
) {
preNode = preNode.right as TreeNode;
} else if (preNode.left) {
preNode = preNode.left;
while (preNode.right) {
preNode = preNode.right;
}
} else {
let pre = preNode.parent as TreeNode;
while (pre.left === preNode) {
preNode = pre;
pre = preNode.parent as TreeNode;
}
preNode = pre;
}
return preNode;
}
/**
* @description Get the next node.
* @return TreeNode about the next node.
*/
next() {
let nextNode: TreeNode = this;
if (nextNode.right) {
nextNode = nextNode.right;
while (nextNode.left) {
nextNode = nextNode.left;
}
} else {
let pre = nextNode.parent as TreeNode;
while (pre.right === nextNode) {
nextNode = pre;
pre = nextNode.parent as TreeNode;
}
if (nextNode.right !== pre) {
nextNode = pre;
}
}
return nextNode;
}
/**
* @description Rotate left.
* @return TreeNode about moved to original position after rotation.
*/
rotateLeft() {
const PP = this.parent as TreeNode;
const V = this.right as TreeNode;
const R = V.left;
if (PP.parent === this) PP.parent = V;
else if (PP.left === this) PP.left = V;
else PP.right = V;
V.parent = PP;
V.left = this;
this.parent = V;
this.right = R;
if (R) R.parent = this;
return V;
}
/**
* @description Rotate left.
* @return TreeNode about moved to original position after rotation.
*/
rotateRight() {
const PP = this.parent as TreeNode;
const F = this.left as TreeNode;
const K = F.right;
if (PP.parent === this) PP.parent = F;
else if (PP.left === this) PP.left = F;
else PP.right = F;
F.parent = PP;
F.right = this;
this.parent = F;
this.left = K;
if (K) K.parent = this;
return F;
}
/**
* @description Remove this.
*/
remove() {
const parent = this.parent as TreeNode;
if (this === parent.left) {
parent.left = undefined;
} else parent.right = undefined;
}
}
export default TreeNode;
js-sdsl-4.1.4/src/container/TreeContainer/Base/index.ts 0000664 0000000 0000000 00000043425 14306031657 0022760 0 ustar 00root root 0000000 0000000 import TreeNode from './TreeNode';
import TreeIterator from './TreeIterator';
import { Container } from '@/container/ContainerBase/index';
import { checkWithinAccessParams } from '@/utils/checkParams';
abstract class TreeContainer extends Container {
protected root: TreeNode | undefined = undefined;
protected header: TreeNode = new TreeNode();
protected cmp: (x: K, y: K) => number;
protected constructor(cmp: (x: K, y: K) => number =
(x: K, y: K) => {
if (x < y) return -1;
if (x > y) return 1;
return 0;
}) {
super();
this.cmp = cmp;
}
/**
* @param curNode The starting node of the search.
* @param key The key you want to search.
* @return TreeNode which key is greater than or equals to the given key.
* @protected
*/
protected _lowerBound(curNode: TreeNode | undefined, key: K) {
let resNode;
while (curNode) {
const cmpResult = this.cmp(curNode.key as K, key);
if (cmpResult < 0) {
curNode = curNode.right;
} else if (cmpResult > 0) {
resNode = curNode;
curNode = curNode.left;
} else return curNode;
}
return resNode === undefined ? this.header : resNode;
}
/**
* @param key The given key you want to compare.
* @return An iterator to the first element not less than the given key.
*/
abstract lowerBound(key: K): TreeIterator;
/**
* @param curNode The starting node of the search.
* @param key The key you want to search.
* @return TreeNode which key is greater than the given key.
* @protected
*/
protected _upperBound(curNode: TreeNode | undefined, key: K) {
let resNode;
while (curNode) {
const cmpResult = this.cmp(curNode.key as K, key);
if (cmpResult <= 0) {
curNode = curNode.right;
} else if (cmpResult > 0) {
resNode = curNode;
curNode = curNode.left;
}
}
return resNode === undefined ? this.header : resNode;
}
/**
* @param key The given key you want to compare.
* @return An iterator to the first element greater than the given key.
*/
abstract upperBound(key: K): TreeIterator;
/**
* @param curNode The starting node of the search.
* @param key The key you want to search.
* @return TreeNode which key is less than or equals to the given key.
* @protected
*/
protected _reverseLowerBound(curNode: TreeNode | undefined, key: K) {
let resNode;
while (curNode) {
const cmpResult = this.cmp(curNode.key as K, key);
if (cmpResult < 0) {
resNode = curNode;
curNode = curNode.right;
} else if (cmpResult > 0) {
curNode = curNode.left;
} else return curNode;
}
return resNode === undefined ? this.header : resNode;
}
/**
* @param key The given key you want to compare.
* @return An iterator to the first element not greater than the given key.
*/
abstract reverseLowerBound(key: K): TreeIterator;
/**
* @param curNode The starting node of the search.
* @param key The key you want to search.
* @return TreeNode which key is less than the given key.
* @protected
*/
protected _reverseUpperBound(curNode: TreeNode | undefined, key: K) {
let resNode;
while (curNode) {
const cmpResult = this.cmp(curNode.key as K, key);
if (cmpResult < 0) {
resNode = curNode;
curNode = curNode.right;
} else if (cmpResult >= 0) {
curNode = curNode.left;
}
}
return resNode === undefined ? this.header : resNode;
}
/**
* @param key The given key you want to compare.
* @return An iterator to the first element less than the given key.
*/
abstract reverseUpperBound(key: K): TreeIterator;
/**
* @description Union the other tree to self.
*
* Waiting for optimization, this is O(mlog(n+m)) algorithm now,
* but we expect it to be O(mlog(n/m+1)).
* More information =>
* https://en.wikipedia.org/wiki/Red_black_tree
*
* @param other The other tree container you want to merge.
*/
abstract union(other: TreeContainer): void;
/**
* @description Make self balance after erase a node.
* @param curNode The node want to remove.
* @protected
*/
protected eraseNodeSelfBalance(curNode: TreeNode) {
while (true) {
const parentNode = curNode.parent as TreeNode;
if (parentNode === this.header) return;
if (curNode.color === TreeNode.RED) {
curNode.color = TreeNode.BLACK;
return;
}
if (curNode === parentNode.left) {
const brother = parentNode.right as TreeNode;
if (brother.color === TreeNode.RED) {
brother.color = TreeNode.BLACK;
parentNode.color = TreeNode.RED;
if (parentNode === this.root) {
this.root = parentNode.rotateLeft();
} else parentNode.rotateLeft();
} else if (brother.color === TreeNode.BLACK) {
if (brother.right && brother.right.color === TreeNode.RED) {
brother.color = parentNode.color;
parentNode.color = TreeNode.BLACK;
brother.right.color = TreeNode.BLACK;
if (parentNode === this.root) {
this.root = parentNode.rotateLeft();
} else parentNode.rotateLeft();
return;
} else if (brother.left && brother.left.color === TreeNode.RED) {
brother.color = TreeNode.RED;
brother.left.color = TreeNode.BLACK;
brother.rotateRight();
} else {
brother.color = TreeNode.RED;
curNode = parentNode;
}
}
} else {
const brother = parentNode.left as TreeNode;
if (brother.color === TreeNode.RED) {
brother.color = TreeNode.BLACK;
parentNode.color = TreeNode.RED;
if (parentNode === this.root) {
this.root = parentNode.rotateRight();
} else parentNode.rotateRight();
} else {
if (brother.left && brother.left.color === TreeNode.RED) {
brother.color = parentNode.color;
parentNode.color = TreeNode.BLACK;
brother.left.color = TreeNode.BLACK;
if (parentNode === this.root) {
this.root = parentNode.rotateRight();
} else parentNode.rotateRight();
return;
} else if (brother.right && brother.right.color === TreeNode.RED) {
brother.color = TreeNode.RED;
brother.right.color = TreeNode.BLACK;
brother.rotateLeft();
} else {
brother.color = TreeNode.RED;
curNode = parentNode;
}
}
}
}
}
/**
* @description Remove a node.
* @param curNode The node you want to remove.
* @protected
*/
protected eraseNode(curNode: TreeNode) {
if (this.length === 1) {
this.clear();
return;
}
let swapNode = curNode;
while (swapNode.left || swapNode.right) {
if (swapNode.right) {
swapNode = swapNode.right;
while (swapNode.left) swapNode = swapNode.left;
} else if (swapNode.left) {
swapNode = swapNode.left;
}
[curNode.key, swapNode.key] = [swapNode.key, curNode.key];
[curNode.value, swapNode.value] = [swapNode.value, curNode.value];
curNode = swapNode;
}
if (this.header.left === swapNode) {
this.header.left = swapNode.parent;
} else if (this.header.right === swapNode) {
this.header.right = swapNode.parent;
}
this.eraseNodeSelfBalance(swapNode);
swapNode.remove();
this.length -= 1;
(this.root as TreeNode).color = TreeNode.BLACK;
}
/**
* @description InOrder traversal the tree.
* @protected
*/
protected inOrderTraversal:
(curNode: TreeNode | undefined, callback: (curNode: TreeNode) => boolean) => boolean =
(curNode: TreeNode | undefined, callback: (curNode: TreeNode) => boolean) => {
if (curNode === undefined) return false;
const ifReturn = this.inOrderTraversal(curNode.left, callback);
if (ifReturn) return true;
if (callback(curNode)) return true;
return this.inOrderTraversal(curNode.right, callback);
};
/**
* @description Make self balance after insert a node.
* @param curNode The node want to insert.
* @protected
*/
protected insertNodeSelfBalance(curNode: TreeNode) {
while (true) {
const parentNode = curNode.parent as TreeNode;
if (parentNode.color === TreeNode.BLACK) return;
const grandParent = parentNode.parent as TreeNode;
if (parentNode === grandParent.left) {
const uncle = grandParent.right;
if (uncle && uncle.color === TreeNode.RED) {
uncle.color = parentNode.color = TreeNode.BLACK;
if (grandParent === this.root) return;
grandParent.color = TreeNode.RED;
curNode = grandParent;
continue;
} else if (curNode === parentNode.right) {
curNode.color = TreeNode.BLACK;
if (curNode.left) curNode.left.parent = parentNode;
if (curNode.right) curNode.right.parent = grandParent;
parentNode.right = curNode.left;
grandParent.left = curNode.right;
curNode.left = parentNode;
curNode.right = grandParent;
if (grandParent === this.root) {
this.root = curNode;
this.header.parent = curNode;
} else {
const GP = grandParent.parent as TreeNode;
if (GP.left === grandParent) {
GP.left = curNode;
} else GP.right = curNode;
}
curNode.parent = grandParent.parent;
parentNode.parent = curNode;
grandParent.parent = curNode;
} else {
parentNode.color = TreeNode.BLACK;
if (grandParent === this.root) {
this.root = grandParent.rotateRight();
} else grandParent.rotateRight();
}
grandParent.color = TreeNode.RED;
} else {
const uncle = grandParent.left;
if (uncle && uncle.color === TreeNode.RED) {
uncle.color = parentNode.color = TreeNode.BLACK;
if (grandParent === this.root) return;
grandParent.color = TreeNode.RED;
curNode = grandParent;
continue;
} else if (curNode === parentNode.left) {
curNode.color = TreeNode.BLACK;
if (curNode.left) curNode.left.parent = grandParent;
if (curNode.right) curNode.right.parent = parentNode;
grandParent.right = curNode.left;
parentNode.left = curNode.right;
curNode.left = grandParent;
curNode.right = parentNode;
if (grandParent === this.root) {
this.root = curNode;
this.header.parent = curNode;
} else {
const GP = grandParent.parent as TreeNode;
if (GP.left === grandParent) {
GP.left = curNode;
} else GP.right = curNode;
}
curNode.parent = grandParent.parent;
parentNode.parent = curNode;
grandParent.parent = curNode;
} else {
parentNode.color = TreeNode.BLACK;
if (grandParent === this.root) {
this.root = grandParent.rotateLeft();
} else grandParent.rotateLeft();
}
grandParent.color = TreeNode.RED;
}
return;
}
}
/**
* @description Find node which key is equals to the given key.
* @param curNode The starting node of the search.
* @param key The key you want to search.
* @protected
*/
protected findElementNode(curNode: TreeNode | undefined, key: K) {
while (curNode) {
const cmpResult = this.cmp(curNode.key as K, key);
if (cmpResult < 0) {
curNode = curNode.right;
} else if (cmpResult > 0) {
curNode = curNode.left;
} else return curNode;
}
return curNode;
}
/**
* @description Insert a key-value pair or set value by the given key.
* @param key The key want to insert.
* @param value The value want to set.
* @param hint You can give an iterator hint to improve insertion efficiency.
* @protected
*/
protected set(key: K, value?: V, hint?: TreeIterator) {
if (this.root === undefined) {
this.length += 1;
this.root = new TreeNode(key, value);
this.root.color = TreeNode.BLACK;
this.root.parent = this.header;
this.header.parent = this.root;
this.header.left = this.root;
this.header.right = this.root;
return;
}
let curNode;
const minNode = this.header.left as TreeNode;
const compareToMin = this.cmp(minNode.key as K, key);
if (compareToMin === 0) {
minNode.value = value;
return;
} else if (compareToMin > 0) {
minNode.left = new TreeNode(key, value);
minNode.left.parent = minNode;
curNode = minNode.left;
this.header.left = curNode;
} else {
const maxNode = this.header.right as TreeNode;
const compareToMax = this.cmp(maxNode.key as K, key);
if (compareToMax === 0) {
maxNode.value = value;
return;
} else if (compareToMax < 0) {
maxNode.right = new TreeNode(key, value);
maxNode.right.parent = maxNode;
curNode = maxNode.right;
this.header.right = curNode;
} else {
if (hint !== undefined) {
// @ts-ignore
const iterNode = hint.node;
if (iterNode !== this.header) {
const iterCmpRes = this.cmp(iterNode.key as K, key);
if (iterCmpRes === 0) {
iterNode.value = value;
return;
} else if (iterCmpRes > 0) {
const preNode = iterNode.pre();
const preCmpRes = this.cmp(preNode.key as K, key);
if (preCmpRes === 0) {
preNode.value = value;
return;
} else if (preCmpRes < 0) {
curNode = new TreeNode(key, value);
if (preNode.right === undefined) {
preNode.right = curNode;
curNode.parent = preNode;
} else {
iterNode.left = curNode;
curNode.parent = iterNode;
}
}
}
}
}
if (curNode === undefined) {
curNode = this.root;
while (true) {
const cmpResult = this.cmp(curNode.key as K, key);
if (cmpResult > 0) {
if (curNode.left === undefined) {
curNode.left = new TreeNode(key, value);
curNode.left.parent = curNode;
curNode = curNode.left;
break;
}
curNode = curNode.left;
} else if (cmpResult < 0) {
if (curNode.right === undefined) {
curNode.right = new TreeNode(key, value);
curNode.right.parent = curNode;
curNode = curNode.right;
break;
}
curNode = curNode.right;
} else {
curNode.value = value;
return;
}
}
}
}
}
this.length += 1;
this.insertNodeSelfBalance(curNode);
}
clear() {
this.length = 0;
this.root = undefined;
this.header.parent = undefined;
this.header.left = this.header.right = undefined;
}
/**
* @description Update node's key by iterator.
* @param iter The iterator you want to change.
* @param key The key you want to update.
* @return Boolean about if the modification is successful.
*/
updateKeyByIterator(iter: TreeIterator, key: K): boolean {
// @ts-ignore
const node = iter.node;
if (node === this.header) {
throw new TypeError('Invalid iterator!');
}
if (this.length === 1) {
node.key = key;
return true;
}
if (node === this.header.left) {
if (this.cmp(node.next().key as K, key) > 0) {
node.key = key;
return true;
}
return false;
}
if (node === this.header.right) {
if (this.cmp(node.pre().key as K, key) < 0) {
node.key = key;
return true;
}
return false;
}
const preKey = node.pre().key as K;
if (this.cmp(preKey, key) >= 0) return false;
const nextKey = node.next().key as K;
if (this.cmp(nextKey, key) <= 0) return false;
node.key = key;
return true;
}
eraseElementByPos(pos: number) {
checkWithinAccessParams(pos, 0, this.length - 1);
let index = 0;
this.inOrderTraversal(this.root, curNode => {
if (pos === index) {
this.eraseNode(curNode);
return true;
}
index += 1;
return false;
});
}
/**
* @description Remove the element of the specified key.
* @param key The key you want to remove.
*/
eraseElementByKey(key: K) {
if (!this.length) return;
const curNode = this.findElementNode(this.root, key);
if (curNode === undefined) return;
this.eraseNode(curNode);
}
eraseElementByIterator(iter: TreeIterator) {
// @ts-ignore
const node = iter.node;
if (node === this.header) {
throw new RangeError('Invalid iterator');
}
if (node.right === undefined) {
iter = iter.next();
}
this.eraseNode(node);
return iter;
}
/**
* @description Get the height of the tree.
* @return Number about the height of the RB-tree.
*/
getHeight() {
if (!this.length) return 0;
const traversal:
(curNode: TreeNode | undefined) => number =
(curNode: TreeNode | undefined) => {
if (!curNode) return 0;
return Math.max(traversal(curNode.left), traversal(curNode.right)) + 1;
};
return traversal(this.root);
}
}
export default TreeContainer;
js-sdsl-4.1.4/src/container/TreeContainer/OrderedMap.ts 0000664 0000000 0000000 00000010436 14306031657 0023015 0 ustar 00root root 0000000 0000000 import { ContainerIterator, initContainer } from '@/container/ContainerBase/index';
import { checkWithinAccessParams } from '@/utils/checkParams';
import TreeContainer from './Base/index';
import TreeIterator from './Base/TreeIterator';
import TreeNode from './Base/TreeNode';
export class OrderedMapIterator extends TreeIterator {
get pointer() {
if (this.node === this.header) {
throw new RangeError('OrderedMap iterator access denied');
}
return new Proxy([] as unknown as [K, V], {
get: (_, props: '0' | '1') => {
if (props === '0') return this.node.key;
else if (props === '1') return this.node.value;
},
set: (_, props: '1', newValue: V) => {
if (props !== '1') {
throw new TypeError('props must be 1');
}
this.node.value = newValue;
return true;
}
});
}
copy() {
return new OrderedMapIterator(this.node, this.header, this.iteratorType);
}
}
class OrderedMap extends TreeContainer {
constructor(container: initContainer<[K, V]> = [], cmp?: (x: K, y: K) => number) {
super(cmp);
this.iterationFunc = this.iterationFunc.bind(this);
container.forEach(([key, value]) => this.setElement(key, value));
}
private readonly iterationFunc:
(curNode: TreeNode | undefined) => Generator<[K, V], void, undefined> =
function * (this: OrderedMap, curNode: TreeNode | undefined) {
if (curNode === undefined) return;
yield * this.iterationFunc(curNode.left);
yield [curNode.key, curNode.value] as [K, V];
yield * this.iterationFunc(curNode.right);
};
begin() {
return new OrderedMapIterator(this.header.left || this.header, this.header);
}
end() {
return new OrderedMapIterator(this.header, this.header);
}
rBegin() {
return new OrderedMapIterator(
this.header.right || this.header,
this.header,
ContainerIterator.REVERSE
);
}
rEnd() {
return new OrderedMapIterator(this.header, this.header, ContainerIterator.REVERSE);
}
front() {
if (!this.length) return undefined;
const minNode = this.header.left as TreeNode;
return [minNode.key, minNode.value] as [K, V];
}
back() {
if (!this.length) return undefined;
const maxNode = this.header.right as TreeNode;
return [maxNode.key, maxNode.value] as [K, V];
}
forEach(callback: (element: [K, V], index: number) => void) {
let index = 0;
for (const pair of this) callback(pair, index++);
}
lowerBound(key: K) {
const resNode = this._lowerBound(this.root, key);
return new OrderedMapIterator(resNode, this.header);
}
upperBound(key: K) {
const resNode = this._upperBound(this.root, key);
return new OrderedMapIterator(resNode, this.header);
}
reverseLowerBound(key: K) {
const resNode = this._reverseLowerBound(this.root, key);
return new OrderedMapIterator(resNode, this.header);
}
reverseUpperBound(key: K) {
const resNode = this._reverseUpperBound(this.root, key);
return new OrderedMapIterator(resNode, this.header);
}
/**
* @description Insert a key-value pair or set value by the given key.
* @param key The key want to insert.
* @param value The value want to set.
* @param hint You can give an iterator hint to improve insertion efficiency.
*/
setElement(key: K, value: V, hint?: OrderedMapIterator) {
this.set(key, value, hint);
}
find(key: K) {
const curNode = this.findElementNode(this.root, key);
if (curNode !== undefined) {
return new OrderedMapIterator(curNode, this.header);
}
return this.end();
}
/**
* @description Get the value of the element of the specified key.
*/
getElementByKey(key: K) {
const curNode = this.findElementNode(this.root, key);
return curNode ? curNode.value : undefined;
}
getElementByPos(pos: number) {
checkWithinAccessParams(pos, 0, this.length - 1);
let res;
let index = 0;
for (const pair of this) {
if (index === pos) {
res = pair;
break;
}
index += 1;
}
return res as [K, V];
}
union(other: OrderedMap) {
other.forEach(([key, value]) => this.setElement(key, value));
}
[Symbol.iterator]() {
return this.iterationFunc(this.root);
}
}
export default OrderedMap;
js-sdsl-4.1.4/src/container/TreeContainer/OrderedSet.ts 0000664 0000000 0000000 00000006672 14306031657 0023042 0 ustar 00root root 0000000 0000000 import TreeContainer from './Base/index';
import { ContainerIterator, initContainer } from '@/container/ContainerBase/index';
import { checkWithinAccessParams } from '@/utils/checkParams';
import TreeIterator from './Base/TreeIterator';
import TreeNode from './Base/TreeNode';
export class OrderedSetIterator extends TreeIterator {
get pointer() {
if (this.node === this.header) {
throw new RangeError('OrderedSet iterator access denied!');
}
return this.node.key as K;
}
copy() {
return new OrderedSetIterator(this.node, this.header, this.iteratorType);
}
}
class OrderedSet extends TreeContainer {
constructor(container: initContainer = [], cmp?: (x: K, y: K) => number) {
super(cmp);
container.forEach((element) => this.insert(element));
this.iterationFunc = this.iterationFunc.bind(this);
}
private readonly iterationFunc:
(curNode: TreeNode | undefined) => Generator =
function * (this: OrderedSet, curNode: TreeNode | undefined) {
if (curNode === undefined) return;
yield * this.iterationFunc(curNode.left);
yield curNode.key as K;
yield * this.iterationFunc(curNode.right);
};
begin() {
return new OrderedSetIterator(
this.header.left || this.header,
this.header
);
}
end() {
return new OrderedSetIterator(this.header, this.header);
}
rBegin() {
return new OrderedSetIterator(
this.header.right || this.header,
this.header,
ContainerIterator.REVERSE
);
}
rEnd() {
return new OrderedSetIterator(this.header, this.header, ContainerIterator.REVERSE);
}
front() {
return this.header.left ? this.header.left.key : undefined;
}
back() {
return this.header.right ? this.header.right.key : undefined;
}
forEach(callback: (element: K, index: number) => void) {
let index = 0;
for (const element of this) callback(element, index++);
}
getElementByPos(pos: number) {
checkWithinAccessParams(pos, 0, this.length - 1);
let res;
let index = 0;
for (const element of this) {
if (index === pos) {
res = element;
}
index += 1;
}
return res as K;
}
/**
* @description Insert element to set.
* @param key The key want to insert.
* @param hint You can give an iterator hint to improve insertion efficiency.
*/
insert(key: K, hint?: OrderedSetIterator) {
this.set(key, undefined, hint);
}
find(element: K) {
const curNode = this.findElementNode(this.root, element);
if (curNode !== undefined) {
return new OrderedSetIterator(curNode, this.header);
}
return this.end();
}
lowerBound(key: K) {
const resNode = this._lowerBound(this.root, key);
return new OrderedSetIterator(resNode, this.header);
}
upperBound(key: K) {
const resNode = this._upperBound(this.root, key);
return new OrderedSetIterator(resNode, this.header);
}
reverseLowerBound(key: K) {
const resNode = this._reverseLowerBound(this.root, key);
return new OrderedSetIterator(resNode, this.header);
}
reverseUpperBound(key: K) {
const resNode = this._reverseUpperBound(this.root, key);
return new OrderedSetIterator(resNode, this.header);
}
union(other: OrderedSet) {
other.forEach((element) => this.insert(element));
}
[Symbol.iterator]() {
return this.iterationFunc(this.root);
}
}
export default OrderedSet;
js-sdsl-4.1.4/src/index.ts 0000664 0000000 0000000 00000002231 14306031657 0015350 0 ustar 00root root 0000000 0000000 export { default as Stack } from '@/container/OtherContainer/Stack';
export { default as Queue } from '@/container/OtherContainer/Queue';
export { default as PriorityQueue } from '@/container/OtherContainer/PriorityQueue';
export { default as Vector, VectorIterator } from '@/container/SequentialContainer/Vector';
export { default as LinkList, LinkListIterator } from '@/container/SequentialContainer/LinkList';
export { default as Deque, DequeIterator } from '@/container/SequentialContainer/Deque';
export { default as OrderedSet, OrderedSetIterator } from '@/container/TreeContainer/OrderedSet';
export { default as OrderedMap, OrderedMapIterator } from '@/container/TreeContainer/OrderedMap';
export { default as HashSet } from '@/container/HashContainer/HashSet';
export { default as HashMap } from '@/container/HashContainer/HashMap';
export { Container, ContainerIterator } from '@/container/ContainerBase/index';
export { default as SequentialContainer } from '@/container/SequentialContainer/Base/index';
export { default as TreeContainer } from '@/container/TreeContainer/Base/index';
export { default as HashContainer } from '@/container/HashContainer/Base/index';
js-sdsl-4.1.4/src/utils/ 0000775 0000000 0000000 00000000000 14306031657 0015033 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/src/utils/checkParams.ts 0000664 0000000 0000000 00000000567 14306031657 0017634 0 ustar 00root root 0000000 0000000 /**
* @description Check if access is out of bounds.
* @param pos The position want to access.
* @param lower The lower bound.
* @param upper The upper bound.
* @return Boolean about if access is out of bounds.
*/
export function checkWithinAccessParams(pos: number, lower: number, upper: number) {
if (pos < lower || pos > upper) {
throw new RangeError();
}
}
js-sdsl-4.1.4/test/ 0000775 0000000 0000000 00000000000 14306031657 0014063 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/test/HashContainerTest/ 0000775 0000000 0000000 00000000000 14306031657 0017451 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/test/HashContainerTest/HashMap.test.ts 0000664 0000000 0000000 00000014216 14306031657 0022324 0 ustar 00root root 0000000 0000000 import { Vector, HashMap, HashContainer } from '@/index';
function generateRandom(low = 0, high = 1e6, fix = 6) {
return (low + Math.random() * (high - low)).toFixed(fix);
}
const arr: string[] = [];
const testNum = 10000;
for (let i = 0; i < testNum; ++i) {
arr.push(generateRandom());
}
function judgeHashMap(myHashMap: HashMap, stdMap: Map) {
expect(myHashMap.size()).toBe(stdMap.size);
stdMap.forEach((value, key) => {
expect(myHashMap.getElementByKey(key)).toEqual(value);
expect(myHashMap.find(key)).toEqual(true);
});
}
describe('HashMap test', () => {
// @ts-ignore
HashContainer.treeifyThreshold = 1;
// @ts-ignore
HashContainer.untreeifyThreshold = 1;
const myHashMap = new HashMap(arr.map((element, index) => [element, index]));
const stdMap = new Map(arr.map((element, index) => [element, index]));
test('HashSet hash function test', () => {
judgeHashMap(
// @ts-ignore
new HashMap(arr.map(x => [Math.floor(Number(x)), 1])),
new Map(arr.map(x => [Math.floor(Number(x)), 1]))
);
});
test('constructor test', () => {
expect(new HashMap().size()).toBe(0);
});
test('HashMap setElement function test', () => {
for (let i = 0; i <= testNum; ++i) {
myHashMap.setElement(i.toString(), i);
stdMap.set(i.toString(), i);
}
for (let i = 0; i <= testNum / 10; ++i) {
myHashMap.setElement(i.toString(), i);
}
for (let i = testNum; i < testNum * 2; ++i) {
const random = generateRandom();
myHashMap.setElement(random, i);
stdMap.set(random, i);
}
judgeHashMap(myHashMap, stdMap);
});
test('HashMap forEach function test', () => {
myHashMap.forEach(([key, value]) => {
expect(stdMap.get(key)).toEqual(value);
});
expect(myHashMap.find('-1')).toEqual(false);
let cnt = 0;
for (const element of myHashMap) {
++cnt;
expect(stdMap.has(element[0])).toEqual(true);
}
expect(cnt).toBe(myHashMap.size());
});
test('HashMap eraseElementByKey function test', () => {
for (let i = 0; i < testNum; ++i) {
const str = i.toString();
myHashMap.eraseElementByKey(str);
stdMap.delete(str);
}
myHashMap.eraseElementByKey('-1');
myHashMap.eraseElementByKey('-2');
myHashMap.eraseElementByKey('-3');
myHashMap.eraseElementByKey('-4');
myHashMap.eraseElementByKey('-5');
myHashMap.eraseElementByKey('-6');
myHashMap.eraseElementByKey('-7');
myHashMap.eraseElementByKey('-8');
myHashMap.eraseElementByKey('-9');
expect(myHashMap.getElementByKey('-1')).toBe(undefined);
expect(myHashMap.getElementByKey('-2')).toBe(undefined);
expect(myHashMap.getElementByKey('-3')).toBe(undefined);
expect(myHashMap.getElementByKey('-4')).toBe(undefined);
expect(myHashMap.getElementByKey('-5')).toBe(undefined);
expect(myHashMap.getElementByKey('-6')).toBe(undefined);
expect(myHashMap.getElementByKey('-7')).toBe(undefined);
expect(myHashMap.getElementByKey('-8')).toBe(undefined);
expect(myHashMap.getElementByKey('-9')).toBe(undefined);
expect(myHashMap.find('-1')).toBe(false);
expect(myHashMap.find('-2')).toBe(false);
expect(myHashMap.find('-3')).toBe(false);
expect(myHashMap.find('-4')).toBe(false);
expect(myHashMap.find('-5')).toBe(false);
expect(myHashMap.find('-6')).toBe(false);
expect(myHashMap.find('-7')).toBe(false);
expect(myHashMap.find('-8')).toBe(false);
expect(myHashMap.find('-9')).toBe(false);
judgeHashMap(myHashMap, stdMap);
});
test('HashMap clear function test', () => {
myHashMap.clear();
stdMap.clear();
judgeHashMap(myHashMap, stdMap);
});
test('HashMap empty test', () => {
myHashMap.eraseElementByKey('1');
expect(myHashMap.find('1')).toEqual(false);
for (let i = -1; i >= -1000; --i) {
expect(myHashMap.getElementByKey(i.toString())).toEqual(undefined);
expect(myHashMap.find(i.toString())).toEqual(false);
}
// @ts-ignore
const bucketNum = myHashMap.bucketNum;
// @ts-ignore
myHashMap.bucketNum = HashContainer.maxBucketNum;
// @ts-ignore
myHashMap.reAllocate();
// @ts-ignore
myHashMap.hashTable[0] = new Vector();
// @ts-ignore
myHashMap.hashTable[myHashMap.bucketNum - 5] = new Vector();
// @ts-ignore
myHashMap.reAllocate(myHashMap.bucketNum);
// @ts-ignore
myHashMap.bucketNum = bucketNum;
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars, no-empty
for (const _ of myHashMap) {}
});
test('HashMap normal test', () => {
// @ts-ignore
HashContainer.treeifyThreshold = 6;
// @ts-ignore
HashContainer.untreeifyThreshold = 8;
const mp = new HashMap();
const stdMap = new Map();
for (let i = 0; i < testNum; ++i) {
const str = i.toString();
mp.setElement(str, i);
stdMap.set(str, i);
}
judgeHashMap(mp, stdMap);
let size = testNum;
for (let i = 0; i < testNum; ++i) {
mp.eraseElementByKey(i.toString());
expect(mp.size()).toEqual(--size);
}
expect(mp.size()).toEqual(0);
});
test('HashSet insert and erase', () => {
// @ts-ignore
HashContainer.treeifyThreshold = 6;
// @ts-ignore
HashContainer.untreeifyThreshold = 8;
const mp = new HashMap();
const stdMap = new Map();
const arr: string[] = [];
for (let i = 0; i < testNum; ++i) {
const random = Math.random().toFixed(6);
mp.setElement(random, i);
stdMap.set(random, i);
arr.push(random);
}
judgeHashMap(mp, stdMap);
for (let i = 0; i < testNum; ++i) {
if (Math.random() > 0.5) {
mp.eraseElementByKey(arr[i]);
stdMap.delete(arr[i]);
}
}
judgeHashMap(mp, stdMap);
arr.length = 0;
for (let i = 0; i < testNum; ++i) {
const random = Math.random().toFixed(6);
mp.setElement(random, i);
stdMap.set(random, i);
arr.push(random);
}
judgeHashMap(mp, stdMap);
for (let i = 0; i < testNum; ++i) {
if (Math.random() > 0.5) {
mp.eraseElementByKey(arr[i]);
stdMap.delete(arr[i]);
}
}
judgeHashMap(mp, stdMap);
});
});
js-sdsl-4.1.4/test/HashContainerTest/HashSet.test.ts 0000664 0000000 0000000 00000010740 14306031657 0022340 0 ustar 00root root 0000000 0000000 import { Vector, HashSet, HashContainer } from '@/index';
function generateRandom(low = 0, high = 1e6, fix = 6) {
return (low + Math.random() * (high - low)).toFixed(fix);
}
const arr: string[] = [];
const testNum = 10000;
for (let i = 0; i < testNum; ++i) {
arr.push(generateRandom());
}
function judgeHashSet(myHashSet: HashSet, stdSet: Set) {
expect(myHashSet.size()).toBe(stdSet.size);
stdSet.forEach((element) => {
expect(myHashSet.find(element)).toEqual(true);
});
}
describe('HashSet test', () => {
// @ts-ignore
HashContainer.treeifyThreshold = 1;
// @ts-ignore
HashContainer.untreeifyThreshold = 1;
test('constructor test', () => {
// eslint-disable-next-line no-new
expect(() => new HashSet([], 28)).toThrow(RangeError);
expect(new HashSet().size()).toBe(0);
});
test('HashSet hash function test', () => {
judgeHashSet(
// @ts-ignore
new HashSet(arr.map(x => Math.floor(Number(x)))),
new Set(arr.map(x => Math.floor(Number(x))))
);
});
const myHashSet = new HashSet(arr);
const stdSet = new Set(arr);
test('HashSet insert function test', () => {
for (let i = 0; i < testNum; ++i) {
myHashSet.insert(i.toString());
stdSet.add(i.toString());
const random = generateRandom();
myHashSet.insert(random);
stdSet.add(random);
}
judgeHashSet(myHashSet, stdSet);
});
test('HashSet forEach function test', () => {
myHashSet.forEach((element) => {
expect(stdSet.has(element)).toEqual(true);
});
let cnt = 0;
for (const element of myHashSet) {
++cnt;
expect(stdSet.has(element)).toEqual(true);
}
expect(cnt).toBe(myHashSet.size());
});
test('HashSet eraseElementByKey function test', () => {
for (let i = 0; i < testNum; ++i) {
myHashSet.eraseElementByKey(arr[i]);
stdSet.delete(arr[i]);
const random = generateRandom();
myHashSet.eraseElementByKey(random);
stdSet.delete(random);
}
judgeHashSet(myHashSet, stdSet);
});
test('HashSet clear function test', () => {
myHashSet.clear();
stdSet.clear();
judgeHashSet(myHashSet, stdSet);
});
test('HashSet empty test', () => {
expect(myHashSet.find('1')).toEqual(false);
myHashSet.insert(arr[0]);
myHashSet.insert(arr[0]);
expect(myHashSet.size()).toBe(1);
// @ts-ignore
const bucketNum = myHashSet.bucketNum;
// @ts-ignore
myHashSet.bucketNum = HashContainer.maxBucketNum;
// @ts-ignore
myHashSet.reAllocate();
// @ts-ignore
myHashSet.hashTable[0] = new Vector();
// @ts-ignore
myHashSet.hashTable[myHashSet.bucketNum - 5] = new Vector();
// @ts-ignore
myHashSet.reAllocate(myHashSet.bucketNum);
// @ts-ignore
myHashSet.bucketNum = bucketNum;
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars, no-empty
for (const _ of myHashSet) {}
});
test('HashSet normal test', () => {
// @ts-ignore
HashContainer.treeifyThreshold = 6;
// @ts-ignore
HashContainer.untreeifyThreshold = 8;
const st = new HashSet();
const stdSet = new Set();
for (let i = 0; i < testNum; ++i) {
st.insert(i.toString());
stdSet.add(i.toString());
}
judgeHashSet(st, stdSet);
let size = testNum;
for (let i = 0; i < testNum; ++i) {
st.eraseElementByKey(i.toString());
expect(st.size()).toEqual(--size);
}
expect(st.size()).toEqual(0);
});
test('HashSet insert and erase', () => {
// @ts-ignore
HashContainer.treeifyThreshold = 6;
// @ts-ignore
HashContainer.untreeifyThreshold = 8;
const st = new HashSet();
const stdSet = new Set();
const arr: string[] = [];
for (let i = 0; i < testNum; ++i) {
const random = Math.random().toFixed(6);
st.insert(random);
stdSet.add(random);
arr.push(random);
}
judgeHashSet(st, stdSet);
for (let i = 0; i < testNum; ++i) {
if (Math.random() > 0.5) {
st.eraseElementByKey(arr[i]);
stdSet.delete(arr[i]);
}
}
judgeHashSet(st, stdSet);
arr.length = 0;
for (let i = 0; i < testNum; ++i) {
const random = Math.random().toFixed(6);
st.insert(random);
stdSet.add(random);
arr.push(random);
}
judgeHashSet(st, stdSet);
for (let i = 0; i < testNum; ++i) {
if (Math.random() > 0.5) {
st.eraseElementByKey(arr[i]);
stdSet.delete(arr[i]);
}
}
judgeHashSet(st, stdSet);
});
});
js-sdsl-4.1.4/test/OtherContainerTest/ 0000775 0000000 0000000 00000000000 14306031657 0017647 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/test/OtherContainerTest/PriorityQueue.test.ts 0000664 0000000 0000000 00000003576 14306031657 0024036 0 ustar 00root root 0000000 0000000 import { Vector, PriorityQueue } from '@/index';
const arr: number[] = [];
const testNum = 10000;
for (let i = 0; i < testNum; ++i) {
arr.push(Math.floor(Math.random() * testNum));
}
function judge(myQueue: PriorityQueue, myVector: Vector) {
while (!myQueue.empty()) {
if (myQueue.size() !== myVector.size()) return false;
const u = myQueue.top();
if (u !== myVector.front()) return false;
myQueue.pop();
myVector.eraseElementByPos(0);
}
return true;
}
describe('PriorityQueue test', () => {
test('PriorityQueue empty insert test', () => {
const myQueue = new PriorityQueue();
myQueue.pop();
expect(myQueue.size()).toEqual(0);
myQueue.push(1);
expect(myQueue.size()).toEqual(1);
expect(myQueue.top()).toEqual(1);
});
const myQueue = new PriorityQueue(arr);
const myVector = new Vector(arr);
test('PriorityQueue size test', () => {
expect(myQueue.size()).toBe(myVector.size());
});
test('PriorityQueue other function test', () => {
for (let i = 0; i < testNum; ++i) {
myQueue.push(i);
myVector.pushBack(i);
}
myVector.sort((x, y) => y - x);
expect(judge(myQueue, myVector)).toEqual(true);
});
test('PriorityQueue clear function test', () => {
myQueue.clear();
myVector.clear();
expect(judge(myQueue, myVector)).toEqual(true);
});
test('init test', () => {
const q = new PriorityQueue([1, 2, 3], undefined, false);
expect(q.top()).toEqual(3);
q.pop();
expect(q.top()).toEqual(2);
q.pop();
expect(q.top()).toEqual(1);
q.pop();
expect(q.top()).toBe(undefined);
const que = new PriorityQueue(new Vector([1, 2, 3]));
expect(que.size()).toEqual(3);
expect(que.top()).toEqual(3);
que.pop();
expect(que.top()).toEqual(2);
que.pop();
expect(que.top()).toEqual(1);
que.pop();
expect(q.top()).toBe(undefined);
});
});
js-sdsl-4.1.4/test/OtherContainerTest/Queue.test.ts 0000664 0000000 0000000 00000002156 14306031657 0022265 0 ustar 00root root 0000000 0000000 import { Vector, Queue } from '@/index';
const arr: number[] = [];
const testNum = 10000;
for (let i = 0; i < testNum; ++i) {
arr.push(Math.floor(Math.random() * testNum));
}
function judge(myQueue: Queue, myVector: Vector) {
while (!myQueue.empty()) {
if (myQueue.size() !== myVector.size()) return false;
const s = myQueue.front();
const v = myVector.front();
if (s !== v) return false;
myQueue.pop();
myVector.eraseElementByPos(0);
}
expect(myQueue.front()).toEqual(undefined);
return true;
}
describe('Queue test', () => {
const myQueue = new Queue(arr);
const myVector = new Vector(arr);
test('Queue size test', () => {
expect(myQueue.size()).toBe(myVector.size());
});
test('Queue clear function test', () => {
myQueue.clear();
myVector.clear();
expect(judge(myQueue, myVector)).toEqual(true);
});
test('Queue other function test', () => {
for (let i = 0; i < testNum; ++i) {
myQueue.push(i);
myVector.pushBack(i);
}
expect(judge(myQueue, myVector)).toEqual(true);
});
});
js-sdsl-4.1.4/test/OtherContainerTest/Stack.test.ts 0000664 0000000 0000000 00000002136 14306031657 0022244 0 ustar 00root root 0000000 0000000 import { Vector, Stack } from '@/index';
const arr: number[] = [];
const testNum = 10000;
for (let i = 0; i < testNum; ++i) {
arr.push(Math.floor(Math.random() * testNum));
}
function judge(myStack: Stack, myVector: Vector) {
while (!myStack.empty()) {
if (myStack.size() !== myVector.size()) return false;
const s = myStack.top();
const v = myVector.back();
if (s !== v) return false;
myStack.pop();
myVector.popBack();
}
expect(myStack.top()).toEqual(undefined);
return true;
}
describe('Stack test', () => {
const myStack = new Stack(arr);
const myVector = new Vector(arr);
test('Stack size test', () => {
expect(myStack.size()).toBe(myVector.size());
});
test('Stack clear function test', () => {
myStack.clear();
myVector.clear();
expect(judge(myStack, myVector)).toEqual(true);
});
test('Stack other function test', () => {
for (let i = 0; i < testNum; ++i) {
myStack.push(i);
myVector.pushBack(i);
}
expect(judge(myStack, myVector)).toEqual(true);
});
});
js-sdsl-4.1.4/test/OtherTest/ 0000775 0000000 0000000 00000000000 14306031657 0016004 5 ustar 00root root 0000000 0000000 js-sdsl-4.1.4/test/OtherTest/constructor.test.ts 0000664 0000000 0000000 00000001054 14306031657 0021717 0 ustar 00root root 0000000 0000000 import {
Vector,
LinkList,
Deque,
OrderedSet,
OrderedMap,
HashSet,
HashMap,
Stack,
Queue,
PriorityQueue
} from '@/index';
const containerArr = [
new Stack(),
new Queue(),
new PriorityQueue(),
new Vector(),
new LinkList(),
new Deque(),
new OrderedSet(),
new OrderedMap(),
new HashSet(),
new HashMap()
];
describe('iterator test', () => {
test('empty constructor test', () => {
for (const container of containerArr) {
expect(container.size()).toEqual(0);
}
});
});
js-sdsl-4.1.4/test/OtherTest/iterator.test.ts 0000664 0000000 0000000 00000013653 14306031657 0021173 0 ustar 00root root 0000000 0000000 import {
Vector,
LinkList,
Deque,
OrderedSet,
OrderedMap,
Container,
ContainerIterator,
VectorIterator,
LinkListIterator,
DequeIterator,
OrderedSetIterator,
OrderedMapIterator,
SequentialContainer,
TreeContainer
} from '@/index';
let arr: number[] = [];
const testNum = 10000;
for (let i = 0; i < testNum; ++i) {
arr.push(Math.floor(Math.random() * testNum));
}
arr = Array.from(new Set(arr));
arr.sort((x, y) => x - y);
const containerArr: Container[] = [
new Vector(arr),
new LinkList(arr),
new Deque(arr),
new OrderedSet(arr),
new OrderedMap(arr.map((element, index) => [index, element]))
];
describe('iterator test', () => {
test('normal iterator next function test', () => {
for (const container of containerArr) {
let index = 0;
for (let it = container.begin() as ContainerIterator;
!it.equals(container.end() as ContainerIterator);
it = it.next()) {
if (container instanceof OrderedMap) {
expect((it as ContainerIterator<[number, number]>).pointer[1])
.toEqual(arr[index++]);
} else {
expect(it.pointer).toEqual(arr[index++]);
}
}
}
});
test('normal iterator pre function test', () => {
for (const container of containerArr) {
let index = arr.length - 1;
for (let it = container.end().pre() as ContainerIterator;
!it.equals(container.begin() as ContainerIterator);
it = it.pre()) {
if (container instanceof OrderedMap) {
expect((it as ContainerIterator<[number, number]>).pointer[1])
.toEqual(arr[index--]);
} else {
expect(it.pointer).toEqual(arr[index--]);
}
}
}
});
test('reverse iterator next function test', () => {
for (const container of containerArr) {
let index = arr.length - 1;
for (let it = container.rBegin() as ContainerIterator;
!it.equals(container.rEnd() as ContainerIterator);
it = it.next()) {
if (container instanceof OrderedMap) {
expect((it as ContainerIterator<[number, number]>).pointer[1])
.toEqual(arr[index--]);
} else {
expect(it.pointer).toEqual(arr[index--]);
}
}
}
});
test('reverse iterator pre function test', () => {
for (const container of containerArr) {
let index = 0;
for (let it = container.rEnd().pre() as ContainerIterator;
!it.equals(container.rBegin() as ContainerIterator);
it = it.pre()) {
if (container instanceof OrderedMap) {
expect((it as ContainerIterator<[number, number]>).pointer[1])
.toEqual(arr[index++]);
} else {
expect(it.pointer).toEqual(arr[index++]);
}
}
}
});
for (const container of containerArr) {
test('normal iterator next run time error test', () => {
expect(() => container.end().next()).toThrowError(RangeError);
});
test('normal iterator pre run time error test', () => {
expect(() => container.begin().pre()).toThrowError(RangeError);
});
test('reverse iterator next run time error test', () => {
expect(() => container.rEnd().next()).toThrowError(RangeError);
});
test('reverse iterator pre run time error test', () => {
expect(() => container.rBegin().pre()).toThrowError(RangeError);
});
}
test('copy test', () => {
for (const container of containerArr) {
const iter = container.begin() as ContainerIterator;
const copy = iter.copy() as ContainerIterator;
iter.next();
expect(iter.equals(copy)).toBe(false);
copy.next();
expect(iter.equals(copy)).toBe(true);
}
for (const container of containerArr) {
const iter = container.end() as ContainerIterator;
const copy = iter.copy() as ContainerIterator;
iter.pre();
expect(iter.equals(copy)).toBe(false);
copy.pre();
expect(iter.equals(copy)).toBe(true);
}
for (const container of containerArr) {
const iter = container.rBegin() as ContainerIterator;
const copy = iter.copy() as ContainerIterator;
iter.next();
expect(iter.equals(copy)).toBe(false);
copy.next();
expect(iter.equals(copy)).toBe(true);
}
for (const container of containerArr) {
const iter = container.rEnd() as ContainerIterator