11// this code is Deno only
22
3+ import { unreachable } from "@std/assert/unreachable" ;
34import { extractResultError , ResultError } from "../compound.ts" ;
45import { PositionedError } from "../parser/parser_lib.ts" ;
5- import { parseDictionary } from "./parser.ts" ;
6+ import { HEADS , parseDictionary } from "./parser.ts" ;
67import { Dictionary } from "./type.ts" ;
78
89const SOURCE = new URL ( "../../dictionary.txt" , import . meta. url ) ;
@@ -27,28 +28,69 @@ export const dictionary: Dictionary = new Map(Object.entries(json));
2728` ;
2829 await Deno . writeTextFile ( DESTINATION , code ) ;
2930}
31+ function buildOffloaded ( src : string ) : Promise < Dictionary > {
32+ return new Promise ( ( resolve , reject ) => {
33+ const worker = new Worker (
34+ new URL ( "./worker.ts" , import . meta. url ) ,
35+ { type : "module" } ,
36+ ) ;
37+ worker . postMessage ( src ) ;
38+ worker . onmessage = ( event ) => {
39+ resolve ( event . data as Dictionary ) ;
40+ worker . terminate ( ) ;
41+ } ;
42+ worker . onerror = ( event ) => {
43+ reject ( event . error ) ;
44+ } ;
45+ } ) ;
46+ }
3047export async function build ( ) : Promise < boolean > {
3148 // deno-lint-ignore no-console
32- console . log ( "Building dictionary..." ) ;
49+ console . log (
50+ `Building dictionary with ${ navigator . hardwareConcurrency } threads...` ,
51+ ) ;
3352 const start = performance . now ( ) ;
3453 const text = await Deno . readTextFile ( SOURCE ) ;
35- const startDictionary = performance . now ( ) ;
36- let dictionary : Dictionary ;
54+ const heads = [ ...text . matchAll ( HEADS ) ] . map ( ( match ) => match . index ) ;
55+ const regionIndices = [ ...new Array ( navigator . hardwareConcurrency ) . keys ( ) ]
56+ . map ( ( index ) => {
57+ const start = index * text . length / navigator . hardwareConcurrency ;
58+ for ( const head of heads ) {
59+ if ( start <= head ) {
60+ return head ;
61+ }
62+ }
63+ } ) ;
64+ const regions = regionIndices . map ( ( index , i ) =>
65+ text . slice ( index , regionIndices [ i + 1 ] ?? text . length )
66+ ) ;
67+ const dictionary : Dictionary = new Map ( ) ;
3768 try {
38- dictionary = parseDictionary ( text ) ;
39- } catch ( error ) {
40- displayError ( text , extractResultError ( error ) ) ;
41- return false ;
69+ const entries = await Promise . all (
70+ regions . map ( ( region ) => buildOffloaded ( region ) ) ,
71+ ) ;
72+ for ( const entry of entries ) {
73+ for ( const [ name , definition ] of entry ) {
74+ if ( dictionary . has ( name ) ) {
75+ throw new Error ( ) ;
76+ }
77+ dictionary . set ( name , definition ) ;
78+ }
79+ }
80+ } catch ( _ ) {
81+ try {
82+ parseDictionary ( text ) ;
83+ } catch ( error ) {
84+ displayError ( `${ SOURCE } ` , extractResultError ( error ) ) ;
85+ return false ;
86+ }
87+ unreachable ( ) ;
4288 }
43- const endDictionary = performance . now ( ) ;
4489 await buildWithDictionary ( dictionary ) ;
4590 const end = performance . now ( ) ;
4691 const total = Math . floor ( end - start ) ;
47- const parsing = Math . floor ( endDictionary - startDictionary ) ;
4892 // deno-lint-ignore no-console
49- console . log (
50- `Building dictionary done in ${ total } ms (parsing dictionary took ${ parsing } ms)` ,
51- ) ;
93+ console . log ( `Building dictionary done in ${ total } ms` ) ;
5294 return true ;
5395}
5496function displayError ( source : string , errors : ReadonlyArray < ResultError > ) {
0 commit comments