@@ -57,9 +57,15 @@ newnfa(struct vars *v,
57
57
return NULL ;
58
58
}
59
59
60
+ /* Make the NFA minimally valid, so freenfa() will behave sanely */
60
61
nfa -> states = NULL ;
61
62
nfa -> slast = NULL ;
62
- nfa -> free = NULL ;
63
+ nfa -> freestates = NULL ;
64
+ nfa -> freearcs = NULL ;
65
+ nfa -> lastsb = NULL ;
66
+ nfa -> lastab = NULL ;
67
+ nfa -> lastsbused = 0 ;
68
+ nfa -> lastabused = 0 ;
63
69
nfa -> nstates = 0 ;
64
70
nfa -> cm = cm ;
65
71
nfa -> v = v ;
@@ -68,9 +74,10 @@ newnfa(struct vars *v,
68
74
nfa -> flags = 0 ;
69
75
nfa -> minmatchall = nfa -> maxmatchall = -1 ;
70
76
nfa -> parent = parent ; /* Precedes newfstate so parent is valid. */
77
+
78
+ /* Create required infrastructure */
71
79
nfa -> post = newfstate (nfa , '@' ); /* number 0 */
72
80
nfa -> pre = newfstate (nfa , '>' ); /* number 1 */
73
-
74
81
nfa -> init = newstate (nfa ); /* may become invalid later */
75
82
nfa -> final = newstate (nfa );
76
83
if (ISERR ())
@@ -99,23 +106,27 @@ newnfa(struct vars *v,
99
106
static void
100
107
freenfa (struct nfa * nfa )
101
108
{
102
- struct state * s ;
109
+ struct statebatch * sb ;
110
+ struct statebatch * sbnext ;
111
+ struct arcbatch * ab ;
112
+ struct arcbatch * abnext ;
103
113
104
- while (( s = nfa -> states ) != NULL )
114
+ for ( sb = nfa -> lastsb ; sb != NULL ; sb = sbnext )
105
115
{
106
- s -> nins = s -> nouts = 0 ; /* don't worry about arcs */
107
- freestate (nfa , s );
116
+ sbnext = sb -> next ;
117
+ nfa -> v -> spaceused -= STATEBATCHSIZE (sb -> nstates );
118
+ FREE (sb );
108
119
}
109
- while ((s = nfa -> free ) != NULL )
120
+ nfa -> lastsb = NULL ;
121
+ for (ab = nfa -> lastab ; ab != NULL ; ab = abnext )
110
122
{
111
- nfa -> free = s -> next ;
112
- destroystate (nfa , s );
123
+ abnext = ab -> next ;
124
+ nfa -> v -> spaceused -= ARCBATCHSIZE (ab -> narcs );
125
+ FREE (ab );
113
126
}
127
+ nfa -> lastab = NULL ;
114
128
115
- nfa -> slast = NULL ;
116
129
nfa -> nstates = -1 ;
117
- nfa -> pre = NULL ;
118
- nfa -> post = NULL ;
119
130
FREE (nfa );
120
131
}
121
132
@@ -138,28 +149,43 @@ newstate(struct nfa *nfa)
138
149
return NULL ;
139
150
}
140
151
141
- if (nfa -> free != NULL )
152
+ /* first, recycle anything that's on the freelist */
153
+ if (nfa -> freestates != NULL )
154
+ {
155
+ s = nfa -> freestates ;
156
+ nfa -> freestates = s -> next ;
157
+ }
158
+ /* otherwise, is there anything left in the last statebatch? */
159
+ else if (nfa -> lastsb != NULL && nfa -> lastsbused < nfa -> lastsb -> nstates )
142
160
{
143
- s = nfa -> free ;
144
- nfa -> free = s -> next ;
161
+ s = & nfa -> lastsb -> s [nfa -> lastsbused ++ ];
145
162
}
163
+ /* otherwise, need to allocate a new statebatch */
146
164
else
147
165
{
166
+ struct statebatch * newSb ;
167
+ size_t nstates ;
168
+
148
169
if (nfa -> v -> spaceused >= REG_MAX_COMPILE_SPACE )
149
170
{
150
171
NERR (REG_ETOOBIG );
151
172
return NULL ;
152
173
}
153
- s = (struct state * ) MALLOC (sizeof (struct state ));
154
- if (s == NULL )
174
+ nstates = (nfa -> lastsb != NULL ) ? nfa -> lastsb -> nstates * 2 : FIRSTSBSIZE ;
175
+ if (nstates > MAXSBSIZE )
176
+ nstates = MAXSBSIZE ;
177
+ newSb = (struct statebatch * ) MALLOC (STATEBATCHSIZE (nstates ));
178
+ if (newSb == NULL )
155
179
{
156
180
NERR (REG_ESPACE );
157
181
return NULL ;
158
182
}
159
- nfa -> v -> spaceused += sizeof (struct state );
160
- s -> oas .next = NULL ;
161
- s -> free = NULL ;
162
- s -> noas = 0 ;
183
+ nfa -> v -> spaceused += STATEBATCHSIZE (nstates );
184
+ newSb -> nstates = nstates ;
185
+ newSb -> next = nfa -> lastsb ;
186
+ nfa -> lastsb = newSb ;
187
+ nfa -> lastsbused = 1 ;
188
+ s = & newSb -> s [0 ];
163
189
}
164
190
165
191
assert (nfa -> nstates >= 0 );
@@ -240,32 +266,8 @@ freestate(struct nfa *nfa,
240
266
nfa -> states = s -> next ;
241
267
}
242
268
s -> prev = NULL ;
243
- s -> next = nfa -> free ; /* don't delete it, put it on the free list */
244
- nfa -> free = s ;
245
- }
246
-
247
- /*
248
- * destroystate - really get rid of an already-freed state
249
- */
250
- static void
251
- destroystate (struct nfa * nfa ,
252
- struct state * s )
253
- {
254
- struct arcbatch * ab ;
255
- struct arcbatch * abnext ;
256
-
257
- assert (s -> no == FREESTATE );
258
- for (ab = s -> oas .next ; ab != NULL ; ab = abnext )
259
- {
260
- abnext = ab -> next ;
261
- FREE (ab );
262
- nfa -> v -> spaceused -= sizeof (struct arcbatch );
263
- }
264
- s -> ins = NULL ;
265
- s -> outs = NULL ;
266
- s -> next = NULL ;
267
- FREE (s );
268
- nfa -> v -> spaceused -= sizeof (struct state );
269
+ s -> next = nfa -> freestates ; /* don't delete it, put it on the free list */
270
+ nfa -> freestates = s ;
269
271
}
270
272
271
273
/*
@@ -334,8 +336,7 @@ createarc(struct nfa *nfa,
334
336
{
335
337
struct arc * a ;
336
338
337
- /* the arc is physically allocated within its from-state */
338
- a = allocarc (nfa , from );
339
+ a = allocarc (nfa );
339
340
if (NISERR ())
340
341
return ;
341
342
assert (a != NULL );
@@ -369,55 +370,52 @@ createarc(struct nfa *nfa,
369
370
}
370
371
371
372
/*
372
- * allocarc - allocate a new out- arc within a state
373
+ * allocarc - allocate a new arc within an NFA
373
374
*/
374
375
static struct arc * /* NULL for failure */
375
- allocarc (struct nfa * nfa ,
376
- struct state * s )
376
+ allocarc (struct nfa * nfa )
377
377
{
378
378
struct arc * a ;
379
379
380
- /* shortcut */
381
- if (s -> free == NULL && s -> noas < ABSIZE )
380
+ /* first, recycle anything that's on the freelist */
381
+ if (nfa -> freearcs != NULL )
382
382
{
383
- a = & s -> oas .a [s -> noas ];
384
- s -> noas ++ ;
385
- return a ;
383
+ a = nfa -> freearcs ;
384
+ nfa -> freearcs = a -> freechain ;
386
385
}
387
-
388
- /* if none at hand, get more */
389
- if (s -> free == NULL )
386
+ /* otherwise, is there anything left in the last arcbatch? */
387
+ else if (nfa -> lastab != NULL && nfa -> lastabused < nfa -> lastab -> narcs )
388
+ {
389
+ a = & nfa -> lastab -> a [nfa -> lastabused ++ ];
390
+ }
391
+ /* otherwise, need to allocate a new arcbatch */
392
+ else
390
393
{
391
394
struct arcbatch * newAb ;
392
- int i ;
395
+ size_t narcs ;
393
396
394
397
if (nfa -> v -> spaceused >= REG_MAX_COMPILE_SPACE )
395
398
{
396
399
NERR (REG_ETOOBIG );
397
400
return NULL ;
398
401
}
399
- newAb = (struct arcbatch * ) MALLOC (sizeof (struct arcbatch ));
402
+ narcs = (nfa -> lastab != NULL ) ? nfa -> lastab -> narcs * 2 : FIRSTABSIZE ;
403
+ if (narcs > MAXABSIZE )
404
+ narcs = MAXABSIZE ;
405
+ newAb = (struct arcbatch * ) MALLOC (ARCBATCHSIZE (narcs ));
400
406
if (newAb == NULL )
401
407
{
402
408
NERR (REG_ESPACE );
403
409
return NULL ;
404
410
}
405
- nfa -> v -> spaceused += sizeof (struct arcbatch );
406
- newAb -> next = s -> oas .next ;
407
- s -> oas .next = newAb ;
408
-
409
- for (i = 0 ; i < ABSIZE ; i ++ )
410
- {
411
- newAb -> a [i ].type = 0 ;
412
- newAb -> a [i ].freechain = & newAb -> a [i + 1 ];
413
- }
414
- newAb -> a [ABSIZE - 1 ].freechain = NULL ;
415
- s -> free = & newAb -> a [0 ];
411
+ nfa -> v -> spaceused += ARCBATCHSIZE (narcs );
412
+ newAb -> narcs = narcs ;
413
+ newAb -> next = nfa -> lastab ;
414
+ nfa -> lastab = newAb ;
415
+ nfa -> lastabused = 1 ;
416
+ a = & newAb -> a [0 ];
416
417
}
417
- assert (s -> free != NULL );
418
418
419
- a = s -> free ;
420
- s -> free = a -> freechain ;
421
419
return a ;
422
420
}
423
421
@@ -478,25 +476,66 @@ freearc(struct nfa *nfa,
478
476
}
479
477
to -> nins -- ;
480
478
481
- /* clean up and place on from-state 's free list */
479
+ /* clean up and place on NFA 's free list */
482
480
victim -> type = 0 ;
483
481
victim -> from = NULL ; /* precautions... */
484
482
victim -> to = NULL ;
485
483
victim -> inchain = NULL ;
486
484
victim -> inchainRev = NULL ;
487
485
victim -> outchain = NULL ;
488
486
victim -> outchainRev = NULL ;
489
- victim -> freechain = from -> free ;
490
- from -> free = victim ;
487
+ victim -> freechain = nfa -> freearcs ;
488
+ nfa -> freearcs = victim ;
491
489
}
492
490
493
491
/*
494
- * changearctarget - flip an arc to have a different to state
492
+ * changearcsource - flip an arc to have a different from state
495
493
*
496
494
* Caller must have verified that there is no pre-existing duplicate arc.
495
+ */
496
+ static void
497
+ changearcsource (struct arc * a , struct state * newfrom )
498
+ {
499
+ struct state * oldfrom = a -> from ;
500
+ struct arc * predecessor ;
501
+
502
+ assert (oldfrom != newfrom );
503
+
504
+ /* take it off old source's out-chain */
505
+ assert (oldfrom != NULL );
506
+ predecessor = a -> outchainRev ;
507
+ if (predecessor == NULL )
508
+ {
509
+ assert (oldfrom -> outs == a );
510
+ oldfrom -> outs = a -> outchain ;
511
+ }
512
+ else
513
+ {
514
+ assert (predecessor -> outchain == a );
515
+ predecessor -> outchain = a -> outchain ;
516
+ }
517
+ if (a -> outchain != NULL )
518
+ {
519
+ assert (a -> outchain -> outchainRev == a );
520
+ a -> outchain -> outchainRev = predecessor ;
521
+ }
522
+ oldfrom -> nouts -- ;
523
+
524
+ a -> from = newfrom ;
525
+
526
+ /* prepend it to new source's out-chain */
527
+ a -> outchain = newfrom -> outs ;
528
+ a -> outchainRev = NULL ;
529
+ if (newfrom -> outs )
530
+ newfrom -> outs -> outchainRev = a ;
531
+ newfrom -> outs = a ;
532
+ newfrom -> nouts ++ ;
533
+ }
534
+
535
+ /*
536
+ * changearctarget - flip an arc to have a different to state
497
537
*
498
- * Note that because we store arcs in their from state, we can't easily have
499
- * a similar changearcsource function.
538
+ * Caller must have verified that there is no pre-existing duplicate arc.
500
539
*/
501
540
static void
502
541
changearctarget (struct arc * a , struct state * newto )
@@ -1009,6 +1048,8 @@ mergeins(struct nfa *nfa,
1009
1048
1010
1049
/*
1011
1050
* moveouts - move all out arcs of a state to another state
1051
+ *
1052
+ * See comments for moveins()
1012
1053
*/
1013
1054
static void
1014
1055
moveouts (struct nfa * nfa ,
@@ -1031,9 +1072,9 @@ moveouts(struct nfa *nfa,
1031
1072
else
1032
1073
{
1033
1074
/*
1034
- * With many arcs, use a sort-merge approach. Note that createarc ()
1035
- * will put new arcs onto the front of newState's chain, so it does
1036
- * not break our walk through the sorted part of the chain.
1075
+ * With many arcs, use a sort-merge approach. Note changearcsource ()
1076
+ * will put the arc onto the front of newState's chain, so it does not
1077
+ * break our walk through the sorted part of the chain.
1037
1078
*/
1038
1079
struct arc * oa ;
1039
1080
struct arc * na ;
@@ -1063,8 +1104,12 @@ moveouts(struct nfa *nfa,
1063
1104
case -1 :
1064
1105
/* newState does not have anything matching oa */
1065
1106
oa = oa -> outchain ;
1066
- createarc (nfa , a -> type , a -> co , newState , a -> to );
1067
- freearc (nfa , a );
1107
+
1108
+ /*
1109
+ * Rather than doing createarc+freearc, we can just unlink
1110
+ * and relink the existing arc struct.
1111
+ */
1112
+ changearcsource (a , newState );
1068
1113
break ;
1069
1114
case 0 :
1070
1115
/* match, advance in both lists */
@@ -1087,8 +1132,7 @@ moveouts(struct nfa *nfa,
1087
1132
struct arc * a = oa ;
1088
1133
1089
1134
oa = oa -> outchain ;
1090
- createarc (nfa , a -> type , a -> co , newState , a -> to );
1091
- freearc (nfa , a );
1135
+ changearcsource (a , newState );
1092
1136
}
1093
1137
}
1094
1138
@@ -3413,7 +3457,6 @@ dumparc(struct arc *a,
3413
3457
FILE * f )
3414
3458
{
3415
3459
struct arc * aa ;
3416
- struct arcbatch * ab ;
3417
3460
3418
3461
fprintf (f , "\t" );
3419
3462
switch (a -> type )
@@ -3451,16 +3494,11 @@ dumparc(struct arc *a,
3451
3494
}
3452
3495
if (a -> from != s )
3453
3496
fprintf (f , "?%d?" , a -> from -> no );
3454
- for (ab = & a -> from -> oas ; ab != NULL ; ab = ab -> next )
3455
- {
3456
- for (aa = & ab -> a [0 ]; aa < & ab -> a [ABSIZE ]; aa ++ )
3457
- if (aa == a )
3458
- break ; /* NOTE BREAK OUT */
3459
- if (aa < & ab -> a [ABSIZE ]) /* propagate break */
3497
+ for (aa = a -> from -> outs ; aa != NULL ; aa = aa -> outchain )
3498
+ if (aa == a )
3460
3499
break ; /* NOTE BREAK OUT */
3461
- }
3462
- if (ab == NULL )
3463
- fprintf (f , "?!?" ); /* not in allocated space */
3500
+ if (aa == NULL )
3501
+ fprintf (f , "?!?" ); /* missing from out-chain */
3464
3502
fprintf (f , "->" );
3465
3503
if (a -> to == NULL )
3466
3504
{
0 commit comments