Skip to content

Commit 56ea93e

Browse files
committed
fix: perf and static calls
1 parent fc00888 commit 56ea93e

14 files changed

Lines changed: 3392 additions & 2417 deletions

.dockerignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
node_modules
2+
dist
3+
.git
4+
.gitignore
5+
.gitmodules
6+
.gitattributes
7+
.vscode
8+
test
9+
*.md
10+
LICENSE

Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM emscripten/emsdk:latest AS build
2+
3+
WORKDIR /src
4+
COPY build-config.mjs build.mjs ./
5+
COPY src/ src/
6+
COPY include/ include/
7+
8+
RUN mkdir -p dist && node build.mjs
9+
10+
FROM alpine
11+
COPY --from=build /src/dist/ /out/

build-config.mjs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import path from 'node:path'
2+
import { fileURLToPath } from 'node:url'
3+
4+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
5+
const inc = path.resolve(__dirname, 'include')
6+
const src = path.resolve(__dirname, 'src')
7+
8+
export const includeDirs = [inc]
9+
10+
export const sources = [
11+
path.resolve(inc, 'anitomy/anitomy.cpp'),
12+
path.resolve(inc, 'anitomy/element.cpp'),
13+
path.resolve(inc, 'anitomy/keyword.cpp'),
14+
path.resolve(inc, 'anitomy/parser.cpp'),
15+
path.resolve(inc, 'anitomy/parser_helper.cpp'),
16+
path.resolve(inc, 'anitomy/parser_number.cpp'),
17+
path.resolve(inc, 'anitomy/string.cpp'),
18+
path.resolve(inc, 'anitomy/token.cpp'),
19+
path.resolve(inc, 'anitomy/tokenizer.cpp'),
20+
path.resolve(src, 'anitomyscript.cpp'),
21+
]
22+
23+
export const outputFile = path.resolve(__dirname, 'dist', 'anitomyscript.js')
24+
25+
export const baseFlags = [
26+
'-std=c++17',
27+
'-fno-exceptions',
28+
'-Wall',
29+
'-Wpedantic',
30+
'-s', 'EXPORT_NAME="anitomyscript"',
31+
'-s', 'WASM=1',
32+
'-s', 'ENVIRONMENT=web,node',
33+
'-s', 'FILESYSTEM=0',
34+
'-s', 'MODULARIZE=1',
35+
'-s', 'EXPORT_ES6=1',
36+
'-s', 'DYNAMIC_EXECUTION=0',
37+
'-s', 'TEXTDECODER=2',
38+
'-s', 'SUPPORT_LONGJMP=0',
39+
'-s', 'EMBIND_AOT=1',
40+
'-s', 'INITIAL_MEMORY=524288',
41+
'-s', 'ALLOW_MEMORY_GROWTH=1',
42+
'-lembind',
43+
]
44+
45+
export const releaseFlags = [
46+
'-O3',
47+
]
48+
49+
export const debugFlags = [
50+
'-O0',
51+
'-g',
52+
'-v',
53+
]

build.mjs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { spawn } from 'node:child_process'
2+
import { baseFlags, releaseFlags, includeDirs, sources, outputFile } from './build-config.mjs'
3+
4+
const includeArgs = includeDirs.flatMap(d => ['-I', d])
5+
6+
const spawnArgs = [
7+
...baseFlags,
8+
...releaseFlags,
9+
...includeArgs,
10+
...sources,
11+
'-o', outputFile,
12+
]
13+
14+
const emcc = process.platform === 'win32' ? 'emcc.bat' : 'emcc'
15+
16+
console.log('Starting Docker build with:', spawnArgs.join(' '))
17+
const s = spawn(emcc, spawnArgs, { stdio: 'inherit' })
18+
19+
s.on('error', (e) => {
20+
console.error('Failed to start emcc:', e)
21+
process.exit(1)
22+
})
23+
24+
s.on('close', (code) => {
25+
process.exit(code ?? 0)
26+
})

dist/anitomyscript.js

Lines changed: 2 additions & 84 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/anitomyscript.wasm

-14.6 KB
Binary file not shown.

gulpfile.js

Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,32 @@
11
import gulp from 'gulp'
22
import { spawn } from 'child_process'
33
import path from 'path'
4-
import fs from 'fs'
4+
import { baseFlags, releaseFlags, debugFlags, includeDirs, sources, outputFile } from './build-config.mjs'
55

6-
function build (cb) {
6+
function getEmcc () {
77
const emscriptenPath = process.env.EMSCRIPTEN || process.env.EMSCRIPTEN_ROOT
8-
9-
if (!emscriptenPath || !fs.existsSync(path.resolve(emscriptenPath))) {
10-
return cb('Unable to find emscripten root. Use the env variable EMSCRIPTEN or EMSCRIPTEN_ROOT to set it manually.')
8+
const emcc = process.platform === 'win32' ? 'emcc.bat' : 'emcc'
9+
if (emscriptenPath) {
10+
return path.join(emscriptenPath, emcc)
1111
}
12+
return emcc
13+
}
1214

13-
const out = path.resolve('./', 'dist', 'anitomyscript.js')
15+
function build (cb) {
1416
const isRelease = process.env.NODE_ENV === 'prod'
15-
16-
let spawnArgs = [
17-
'--memory-init-file', '0',
18-
'-std=c++14',
19-
'-fPIC', '-fno-exceptions', '-Wall', '-Wextra', '-Wpedantic', '-Werror',
20-
'--bind',
21-
'-v',
22-
'-I', path.resolve('./include'),
23-
'-s', 'EXPORT_NAME="anitomyscript"',
24-
'-s', 'WASM=1',
25-
'-s', 'ENVIRONMENT=web,node',
26-
'-s', 'FILESYSTEM=0',
27-
'-s', 'MODULARIZE=1',
28-
'-s', 'EXPORT_ES6=1',
29-
'-s', 'AUTO_JS_LIBRARIES=0',
30-
'-s', 'AUTO_NATIVE_LIBRARIES=0',
31-
'-s', 'HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS=0',
32-
'-s', 'USE_SDL=0',
33-
'-s', 'INITIAL_MEMORY=5308416',
34-
'-s', 'ALLOW_MEMORY_GROWTH=1',
35-
'--no-heap-copy',
36-
path.resolve('./include/anitomy/anitomy.cpp'),
37-
path.resolve('./include/anitomy/element.cpp'),
38-
path.resolve('./include/anitomy/keyword.cpp'),
39-
path.resolve('./include/anitomy/parser.cpp'),
40-
path.resolve('./include/anitomy/parser_helper.cpp'),
41-
path.resolve('./include/anitomy/parser_number.cpp'),
42-
path.resolve('./include/anitomy/string.cpp'),
43-
path.resolve('./include/anitomy/token.cpp'),
44-
path.resolve('./include/anitomy/tokenizer.cpp'),
45-
path.resolve('./src/anitomyscript.cpp'),
46-
'-o', out
17+
const includeArgs = includeDirs.flatMap(d => ['-I', d])
18+
19+
const spawnArgs = [
20+
...baseFlags,
21+
...(isRelease ? releaseFlags : debugFlags),
22+
...includeArgs,
23+
...sources,
24+
'-o', outputFile,
4725
]
4826

49-
if (isRelease) {
50-
spawnArgs = spawnArgs.concat([
51-
'-O3',
52-
'-s', 'USE_CLOSURE_COMPILER=1',
53-
'-s', 'IGNORE_CLOSURE_COMPILER_ERRORS=1',
54-
'--closure', '1',
55-
'--llvm-lto', '3'
56-
])
57-
}
58-
59-
console.log(`Starting ${isRelease ? 'release' : 'debug'} build with emcc args`, spawnArgs)
60-
const emccExec = process.platform === 'win32' ? 'emcc.bat' : 'emcc'
61-
const s = spawn(path.join(emscriptenPath, emccExec), spawnArgs, {
62-
cwd: './dist'
63-
})
27+
console.log(`Starting ${isRelease ? 'release' : 'debug'} build`)
28+
const emcc = getEmcc()
29+
const s = spawn(emcc, spawnArgs)
6430

6531
s.stdout.on('data', (data) => {
6632
console.log(data.toString())

include

Submodule include updated 65 files

index.js

Lines changed: 40 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,47 @@
11
import AnitomyNative from './dist/anitomyscript.js'
2-
let anitomyModule
32

4-
export default async function (file) {
5-
if (!Array.isArray(file) && typeof file !== 'string') {
6-
return new Error('Input must be either an Array or a string')
3+
const FIELDS = [
4+
'anime_season', 'season_prefix', 'anime_title',
5+
'anime_type', 'anime_year', 'audio_term',
6+
'device_compatibility', 'episode_number', 'episode_number_alt',
7+
'episode_prefix', 'episode_title', 'file_checksum',
8+
'file_extension', 'file_name', 'language',
9+
'other', 'release_group', 'release_information',
10+
'release_version', 'source', 'subtitles',
11+
'video_resolution', 'video_term', 'volume_number',
12+
'volume_prefix', 'unknown',
13+
]
14+
15+
let modPromise, pairs
16+
17+
export default async function parse (input) {
18+
if (!Array.isArray(input) && typeof input !== 'string') {
19+
throw new Error('Input must be either an Array or a string')
720
}
821

9-
if (anitomyModule) {
10-
return parse(file)
11-
}
12-
13-
anitomyModule = await AnitomyNative()
14-
return parse(file)
15-
}
16-
17-
async function parse (file) {
18-
const vector = mapArray(file)
19-
const result = mapVector(anitomyModule.parseMultiple(vector))
20-
vector.delete()
21-
return result.map((each) => elements(each))
22-
}
23-
24-
function elements (elements) {
25-
const returnObj = {
26-
anime_season: elementEntry(elements, anitomyModule.ElementCategory.kElementAnimeSeason),
27-
season_prefix: elementEntry(elements, anitomyModule.ElementCategory.kElementAnimeSeasonPrefix),
28-
anime_title: elementEntry(elements, anitomyModule.ElementCategory.kElementAnimeTitle),
29-
anime_type: elementEntry(elements, anitomyModule.ElementCategory.kElementAnimeType),
30-
anime_year: elementEntry(elements, anitomyModule.ElementCategory.kElementAnimeYear),
31-
audio_term: elementEntry(elements, anitomyModule.ElementCategory.kElementAudioTerm),
32-
device_compatibility: elementEntry(elements, anitomyModule.ElementCategory.kElementDeviceCompatibility),
33-
episode_number: elementEntry(elements, anitomyModule.ElementCategory.kElementEpisodeNumber),
34-
episode_prefix: elementEntry(elements, anitomyModule.ElementCategory.kElementEpisodePrefix),
35-
episode_title: elementEntry(elements, anitomyModule.ElementCategory.kElementEpisodeTitle),
36-
file_checksum: elementEntry(elements, anitomyModule.ElementCategory.kElementFileChecksum),
37-
file_extension: elementEntry(elements, anitomyModule.ElementCategory.kElementFileExtension),
38-
file_name: elementEntry(elements, anitomyModule.ElementCategory.kElementFileName),
39-
language: elementEntry(elements, anitomyModule.ElementCategory.kElementLanguage),
40-
other: elementEntry(elements, anitomyModule.ElementCategory.kElementOther),
41-
release_group: elementEntry(elements, anitomyModule.ElementCategory.kElementReleaseGroup),
42-
release_information: elementEntry(elements, anitomyModule.ElementCategory.kElementReleaseInformation),
43-
release_version: elementEntry(elements, anitomyModule.ElementCategory.kElementReleaseVersion),
44-
source: elementEntry(elements, anitomyModule.ElementCategory.kElementSource),
45-
subtitles: elementEntry(elements, anitomyModule.ElementCategory.kElementSubtitles),
46-
video_resolution: elementEntry(elements, anitomyModule.ElementCategory.kElementVideoResolution),
47-
video_term: elementEntry(elements, anitomyModule.ElementCategory.kElementVideoTerm),
48-
volume_number: elementEntry(elements, anitomyModule.ElementCategory.kElementVolumeNumber),
49-
volume_prefix: elementEntry(elements, anitomyModule.ElementCategory.kElementVolumePrefix),
50-
unknown: elementEntry(elements, anitomyModule.ElementCategory.kElementUnknown)
51-
}
52-
elements.delete()
53-
return returnObj
54-
}
55-
56-
function elementEntry (elements, key) {
57-
return mapVector(elements.get_all(key))
58-
}
59-
60-
function mapArray (array) {
61-
const vector = new anitomyModule.StringVector()
62-
array.forEach((element, index) => {
63-
if (typeof element !== 'string') {
64-
throw new Error(`Element at index ${index} is not a string`)
22+
const mod = await (modPromise ??= AnitomyNative())
23+
pairs ??= FIELDS.map((name, i) => [mod.ElementCategory.values[i], name])
24+
const files = typeof input === 'string' ? [input] : input
25+
const anit = new mod.Anitomy()
26+
const results = []
27+
28+
try {
29+
for (let i = 0; i < files.length; i++) {
30+
const file = files[i]
31+
if (typeof file !== 'string') throw new Error(`Element at index ${i} is not a string`)
32+
anit.parse(file)
33+
const obj = {}
34+
for (const [cat, field] of pairs) {
35+
const vec = anit.get_all(cat)
36+
const length = vec.size()
37+
if (!length) continue
38+
obj[field] = Array.from({ length }, (_, j) => vec.get(j))
39+
}
40+
results.push(obj)
6541
}
66-
vector.push_back(element)
67-
})
68-
return vector
69-
}
70-
71-
function mapVector (vector) {
72-
const array = []
73-
for (let index = 0; index < vector.size(); index++) {
74-
array.push(vector.get(index))
42+
} finally {
43+
anit.delete()
7544
}
76-
vector.delete()
77-
return array
45+
46+
return results
7847
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"scripts": {
88
"test": "mocha test/*.spec.js",
99
"build": "cross-env NODE_ENV=prod gulp",
10-
"build:dev": "cross-env NODE_ENV=dev gulp"
10+
"build:dev": "cross-env NODE_ENV=dev gulp",
11+
"build:docker": "docker build -t anitomyscript-builder -f Dockerfile . && docker create --name tmp-extract anitomyscript-builder && docker cp tmp-extract:/out/. dist/ && docker rm tmp-extract"
1112
},
1213
"files": [
1314
"index.js",

0 commit comments

Comments
 (0)