Skip to content

Commit bdd95e9

Browse files
🚧 progress: First draft.
1 parent b746922 commit bdd95e9

File tree

8 files changed

+10151
-27
lines changed

8 files changed

+10151
-27
lines changed

Diff for: README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
Longest prefix/suffix array for JavaScript.
55
See [docs](https://string-data-structure.github.io/longest-prefix-suffix-array/index.html).
66

7-
> :building_construction: Caveat emptor! This is work in progress. Code may be
8-
> working. Documentation may be present. Coherence may be. Maybe.
9-
10-
> :warning: Depending on your environment, the code may require
11-
> `regeneratorRuntime` to be defined, for instance by importing
12-
> [regenerator-runtime/runtime](https://www.npmjs.com/package/regenerator-runtime).
7+
```js
8+
import {build} from '@string-data-structure/longest-prefix-suffix-array';
9+
const s = 'abracadabra';
10+
const t = new Int32Array(s.length + 1);
11+
build(s, 0, s.length, t, 0);
12+
```
1313

1414
[![License](https://img.shields.io/github/license/string-data-structure/longest-prefix-suffix-array.svg)](https://raw.githubusercontent.com/string-data-structure/longest-prefix-suffix-array/main/LICENSE)
1515
[![Version](https://img.shields.io/npm/v/@string-data-structure/longest-prefix-suffix-array.svg)](https://www.npmjs.org/package/@string-data-structure/longest-prefix-suffix-array)

Diff for: doc/manual/usage.md

+3-14
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
11
# Usage
22

3-
> :warning: Depending on your environment, the code may require
4-
> `regeneratorRuntime` to be defined, for instance by importing
5-
> [regenerator-runtime/runtime](https://www.npmjs.com/package/regenerator-runtime).
6-
7-
First, require the polyfill at the entry point of your application
8-
```js
9-
require( 'regenerator-runtime/runtime' ) ;
10-
// or
11-
import 'regenerator-runtime/runtime.js' ;
12-
```
13-
14-
Then, import the library where needed
3+
Import the library where needed
154
```js
16-
const longestPrefixSuffixArray = require( '@string-data-structure/longest-prefix-suffix-array' ) ;
5+
const {build} = require( '@string-data-structure/longest-prefix-suffix-array' ) ;
176
// or
18-
import * as longestPrefixSuffixArray from '@string-data-structure/longest-prefix-suffix-array' ;
7+
import {build} from '@string-data-structure/longest-prefix-suffix-array' ;
198
```

Diff for: src/build.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Computes for each j the largest 0 <= i < j such that
3+
* p.slice(0, i) is p.slice(j-i, j).
4+
*
5+
* @param {ArrayLike} p
6+
* @param {number} pi
7+
* @param {number} pj
8+
* @param {number[]} t
9+
* @param {number} ti
10+
*/
11+
const build = (p, pi, pj, t, ti) => {
12+
t[ti] = -1;
13+
let si = ti;
14+
let m = -1;
15+
for (let i = pi; i < pj; ++i) {
16+
while (m >= 0 && p[i] !== p[pi + m]) m = t[ti + m];
17+
t[++si] = ++m;
18+
}
19+
};
20+
21+
export default build;

Diff for: src/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
const answer = 42;
2-
export default answer;
1+
export {default as build} from './build.js';

Diff for: test/src/_fixtures.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import {build} from '../../src/index.js';
2+
3+
const _lpsa = (p, pi, pj) => {
4+
// eslint-disable-next-line unicorn/no-new-array
5+
const t = new Array(pj - pi + 1);
6+
build(p, pi, pj, t, 0);
7+
return t;
8+
};
9+
10+
export const lpsa = (input) => _lpsa(input, 0, input.length);

Diff for: test/src/api.js

-5
This file was deleted.

Diff for: test/src/longestPrefixSuffixArray.js

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import test from 'ava';
2+
3+
import {lpsa} from './_fixtures.js';
4+
5+
const isLongestPrefixSuffixArray = (t, table, input) => {
6+
t.is(table[0], -1);
7+
for (let i = 1; i <= input.length; ++i) {
8+
t.not(table[i], -1);
9+
// Prefix and suffix match
10+
t.is(input.slice(0, table[i]), input.slice(i - table[i], i));
11+
if (table[i] + 1 < i) {
12+
// A longer prefix/suffix pair does not match
13+
t.not(input.slice(0, table[i] + 1), input.slice(i - (table[i] + 1), i));
14+
}
15+
}
16+
};
17+
18+
const macro = (t, input, expected) => {
19+
const table = lpsa(input);
20+
t.deepEqual(table, expected);
21+
isLongestPrefixSuffixArray(t, table, input);
22+
};
23+
24+
macro.title = (title, input, expected) =>
25+
title ?? `lpsa(${input}) is ${JSON.stringify(expected)}`;
26+
27+
const auto = (t, input) => {
28+
const table = lpsa(input);
29+
isLongestPrefixSuffixArray(t, table, input);
30+
};
31+
32+
auto.title = (title, input) =>
33+
title ?? `isLongestPrefixSuffixArray(lpsa(${input}))`;
34+
35+
test(macro, '', [-1]);
36+
test(macro, 'abcd', [-1, 0, 0, 0, 0]);
37+
test(macro, 'aaaa', [-1, 0, 1, 2, 3]);
38+
test(macro, 'axax', [-1, 0, 0, 1, 2]);
39+
test(macro, 'axxa', [-1, 0, 0, 0, 1]);
40+
test(macro, 'aaaab', [-1, 0, 1, 2, 3, 0]);
41+
test(macro, 'abcabcacab', [-1, 0, 0, 0, 1, 2, 3, 4, 0, 1, 2]);
42+
test(macro, 'abracadabra', [-1, 0, 0, 0, 1, 0, 1, 0, 1, 2, 3, 4]);
43+
test(
44+
macro,
45+
'abaababaabaababaababa',
46+
[-1, 0, 0, 1, 1, 2, 3, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9, 10, 11, 7, 8],
47+
);
48+
49+
test(auto, 'eifoiwhfeldkasjflkdshfldshflkkdadkkkkkkkkkkkkasjfdljfdleifo');
50+
test(auto, 'aaaaaaaaaaaabbbbbbbbbbaaaaaaaaabbbbbbbb');

0 commit comments

Comments
 (0)