1919import static com .indoqa .fsa .character .CharDataAccessor .*;
2020
2121import java .io .*;
22+ import java .text .NumberFormat ;
2223import java .util .*;
2324import java .util .Map .Entry ;
2425import java .util .function .Consumer ;
@@ -29,12 +30,14 @@ public class CharAcceptorBuilder implements AcceptorBuilder {
2930
3031public static final int FILE_VERSION =2 ;
3132public static final int DEFAULT_CAPACITY_INCREMENT =16 *1024 ;
33+ public static final int DEFAULT_SHRINK_LIMIT =1_000 ;
3234
3335private final boolean caseSensitive ;
3436
3537private char [][]nodes =new char [0 ][];
3638private int nodeCount ;
37- private int capacityIncrement ;
39+ private final int capacityIncrement ;
40+ private final int shrinkLimit ;
3841
3942private Replacements replacements ;
4043
@@ -45,14 +48,15 @@ public class CharAcceptorBuilder implements AcceptorBuilder {
4548private int requiredLength ;
4649
4750public CharAcceptorBuilder (boolean caseSensitive ) {
48- this (caseSensitive ,DEFAULT_CAPACITY_INCREMENT );
51+ this (caseSensitive ,DEFAULT_CAPACITY_INCREMENT , DEFAULT_SHRINK_LIMIT );
4952 }
5053
51- public CharAcceptorBuilder (boolean caseSensitive ,int capacityIncrement ) {
54+ public CharAcceptorBuilder (boolean caseSensitive ,int capacityIncrement , int shrinkLimit ) {
5255super ();
5356
5457this .caseSensitive =caseSensitive ;
5558this .capacityIncrement =capacityIncrement ;
59+ this .shrinkLimit =shrinkLimit ;
5660this .addNode ();
5761 }
5862
@@ -88,6 +92,10 @@ public static CharAcceptor read(InputStream inputStream) throws IOException {
8892return new CharAcceptor (data ,caseSensitive );
8993 }
9094
95+ private static String formatNumber (long number ) {
96+ return NumberFormat .getInstance (Locale .ENGLISH ).format (number );
97+ }
98+
9199private static String getKey (char []node ) {
92100StringBuilder stringBuilder =new StringBuilder ();
93101
@@ -231,26 +239,6 @@ private void addNode() {
231239this .nodeCount ++;
232240 }
233241
234- private Set <String >applyReplacements () {
235- this .sendMessage ("Applying " +this .replacements .getCount () +" replacements" );
236-
237- Set <String >result =new HashSet <>();
238-
239- for (int i =0 ;i <this .nodeCount ;i ++) {
240- char []node =this .nodes [i ];
241- if (node ==null ) {
242- continue ;
243- }
244-
245- boolean updated =this .applyReplacements (node );
246- if (updated ) {
247- result .add (getKey (node ));
248- }
249- }
250-
251- return result ;
252- }
253-
254242private boolean applyReplacements (char []nodeData ) {
255243boolean result =false ;
256244
@@ -275,6 +263,25 @@ private boolean applyReplacements(char[] nodeData) {
275263return result ;
276264 }
277265
266+ private void applyReplacements (Set <String >changedGroups ) {
267+ this .sendMessage ("Applying " +formatNumber (this .replacements .getCount ()) +" replacements" );
268+ if (changedGroups !=null ) {
269+ changedGroups .clear ();
270+ }
271+
272+ for (int i =0 ;i <this .nodeCount ;i ++) {
273+ char []node =this .nodes [i ];
274+ if (node ==null ) {
275+ continue ;
276+ }
277+
278+ boolean updated =this .applyReplacements (node );
279+ if (updated &&changedGroups !=null ) {
280+ changedGroups .add (getKey (node ));
281+ }
282+ }
283+ }
284+
278285private char []buildData () {
279286char []data =new char [this .requiredLength ];
280287int offset =0 ;
@@ -317,7 +324,6 @@ private Map<String, List<NodeReference>> buildGroups() {
317324 }
318325 }
319326
320- this .sendMessage ("Built " +result .size () +" groups" );
321327return result ;
322328 }
323329
@@ -353,17 +359,37 @@ private void findReplacements(List<NodeReference> group) {
353359 }
354360 }
355361
362+ private long getSize () {
363+ long length =0 ;
364+
365+ for (int i =0 ;i <this .nodeCount ;i ++) {
366+ char []node =this .nodes [i ];
367+ if (node ==null ) {
368+ continue ;
369+ }
370+
371+ if (node .length !=0 ) {
372+ length +=node .length ;
373+ }
374+ }
375+
376+ return length ;
377+ }
378+
356379private void minify () {
357380if (this .minified ) {
358381return ;
359382 }
360383
361- this .sendMessage ("Minifying " +this .nodeCount +" nodes" );
384+ long start =System .currentTimeMillis ();
385+ long previousSize =this .getSize ();
386+ this .sendMessage ("Minifying " +formatNumber (this .nodeCount ) +" nodes" );
362387
363388Map <String ,List <NodeReference >>groups =this .buildGroups ();
364- this .replacements .clear ();
389+ Set <String >changedGroups =new HashSet <>();
390+
365391this .findEndNodeReplacements ();
366- Set < String > changedGroups = this .applyReplacements ();
392+ this .applyReplacements (changedGroups );
367393
368394while (true ) {
369395this .replacements .clear ();
@@ -377,13 +403,32 @@ private void minify() {
377403this .findReplacements (group );
378404 }
379405
380- if (this .replacements .getCount () == 0 ) {
406+ if (this .replacements .isEmpty () ) {
381407break ;
382408 }
383409
384- changedGroups =this .applyReplacements ();
410+ this .applyReplacements (changedGroups );
411+
412+ long size =this .getSize ();
413+ long shrunk =previousSize -size ;
414+ long minShrink =previousSize /this .shrinkLimit ;
415+ this .sendMessage (
416+ "Shrunk size by " +formatNumber (shrunk ) +" (from " +formatNumber (previousSize ) +" to " +formatNumber (size ) +"), "
417+ +formatNumber ((System .currentTimeMillis () -start ) /1_000 ) +" seconds" );
418+
419+ if (shrunk <minShrink ) {
420+ this .sendMessage (
421+ "Shrinking step smaller than limit (" +formatNumber (shrunk ) +" < " +formatNumber (minShrink )
422+ +"). Aborting ..." );
423+ break ;
424+ }
425+
426+ previousSize =size ;
385427 }
386428
429+ long duration =System .currentTimeMillis () -start ;
430+ this .sendMessage ("Minified in " +formatNumber (duration /1_000 ) +" seconds" );
431+
387432this .minified =true ;
388433 }
389434
@@ -409,9 +454,9 @@ private void remap() {
409454 }
410455 }
411456
412- this .sendMessage ("RequiredLength: " +this .requiredLength );
457+ this .sendMessage ("Required length " +formatNumber ( this .requiredLength ) );
413458
414- this .applyReplacements ();
459+ this .applyReplacements (( Set < String >) null );
415460
416461this .remapped =true ;
417462 }