• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *******************************************************************************
3  * Copyright (C) 2002-2012, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  */
7 package org.unicode.cldr.util;
8 
9 import java.util.ArrayList;
10 import java.util.Arrays;
11 import java.util.HashSet;
12 import java.util.Random;
13 import java.util.Set;
14 
15 import com.ibm.icu.text.UTF16;
16 import com.ibm.icu.text.UnicodeSet;
17 
18 abstract public class Pick {
19     private static boolean DEBUG = false;
20 
21     // for using to get strings
22 
23     static class Target {
24         private Pick pick;
25         private Random random;
26         private Quoter quoter;
27 
make(Pick pick, Random random, Quoter quoter)28         public static Target make(Pick pick, Random random, Quoter quoter) {
29             Target result = new Target();
30             result.pick = pick;
31             result.random = random;
32             result.quoter = quoter;
33             return result;
34         }
35 
next()36         public String next() {
37             quoter.clear();
38             pick.addTo(this);
39             return get();
40         }
41 
get()42         public String get() {
43             return quoter.toString();
44         }
45 
copyState(Target other)46         private void copyState(Target other) {
47             random = other.random;
48         }
49 
clear()50         private void clear() {
51             quoter.clear();
52         }
53 
54         /*private int length() {
55             return quoter.length();
56         }*/
append(int codepoint)57         private Target append(int codepoint) {
58             quoter.append(codepoint);
59             return this;
60         }
61 
append(String s)62         private Target append(String s) {
63             quoter.append(s);
64             return this;
65         }
66 
67         // must return value between 0 (inc) and 1 (exc)
nextDouble()68         private double nextDouble() {
69             return random.nextDouble();
70         }
71     }
72 
73     // for Building
74 
replace(String toReplace, Pick replacement)75     public Pick replace(String toReplace, Pick replacement) {
76         Replacer visitor = new Replacer(toReplace, replacement);
77         return visit(visitor);
78     }
79 
name(String nameStr)80     public Pick name(String nameStr) {
81         name = nameStr;
82         return this;
83     }
84 
makeSequence()85     static public Pick.Sequence makeSequence() {
86         return new Sequence();
87     }
88 
makeAlternation()89     static public Pick.Alternation makeAlternation() {
90         return new Alternation();
91     }
92     /*
93     static public Pick.Sequence and(Object item) {
94         return new Sequence().and2(item);
95     }
96     static public Pick.Sequence and(Object[] items) {
97         return new Sequence().and2(items);
98     }
99     static public Pick.Alternation or(int itemWeight, Object item) {
100         return new Alternation().or2(itemWeight, item);
101     }
102     static public Pick.Alternation or(Object[] items) {
103         return new Alternation().or2(1, items);
104     }
105     static public Pick.Alternation or(int itemWeight, Object[] items) {
106         return new Alternation().or2(itemWeight, items);
107     }
108     static public Pick.Alternation or(int[] itemWeights, Object[] items) {
109         return new Alternation().or2(itemWeights, items);
110     }
111 
112     static public Pick maybe(int percent, Object item) {
113         return new Repeat(0, 1, new int[]{100-percent, percent}, item);
114         //return Pick.or(1.0-percent, NOTHING).or2(percent, item);
115     }
116     static public Pick repeat(int minCount, int maxCount, int itemWeights, Object item) {
117         return new Repeat(minCount, maxCount, itemWeights, item);
118     }
119 
120     static public Pick codePoint(String source) {
121         return new CodePoint(new UnicodeSet(source));
122     }
123     */
124 
repeat(int minCount, int maxCount, int[] itemWeights, Pick item)125     static public Pick repeat(int minCount, int maxCount, int[] itemWeights, Pick item) {
126         return new Repeat(minCount, maxCount, itemWeights, item);
127     }
128 
codePoint(UnicodeSet source)129     static public Pick codePoint(UnicodeSet source) {
130         return new CodePoint(source);
131     }
132 
string(String source)133     static public Pick string(String source) {
134         return new Literal(source);
135     }
136     /*
137     static public Pick unquoted(String source) {
138         return new Literal(source);
139     }
140     static public Pick string(int minLength, int maxLength, Pick item) {
141         return new Morph(item, minLength, maxLength);
142     }
143     */
144 
getInternal(int depth, Set alreadySeen)145     public abstract String getInternal(int depth, Set alreadySeen);
146     // Internals
147 
148     protected String name;
149 
addTo(Target target)150     protected abstract void addTo(Target target);
151 
match(String input, Position p)152     public abstract boolean match(String input, Position p);
153 
154     public static class Sequence extends ListPick {
and2(Pick item)155         public Sequence and2(Pick item) {
156             addInternal(new Pick[] { item }); // we don't care about perf
157             return this; // for chaining
158         }
159 
and2(Pick[] itemArray)160         public Sequence and2(Pick[] itemArray) {
161             addInternal(itemArray);
162             return this; // for chaining
163         }
164 
165         @Override
addTo(Target target)166         protected void addTo(Target target) {
167             for (int i = 0; i < items.length; ++i) {
168                 items[i].addTo(target);
169             }
170         }
171 
172         @Override
getInternal(int depth, Set alreadySeen)173         public String getInternal(int depth, Set alreadySeen) {
174             String result = checkName(name, alreadySeen);
175             if (result.startsWith("$")) return result;
176             result = indent(depth) + result + "SEQ(";
177             for (int i = 0; i < items.length; ++i) {
178                 if (i != 0) result += ", ";
179                 result += items[i].getInternal(depth + 1, alreadySeen);
180             }
181             result += ")";
182             return result;
183         }
184 
185         // keep private
Sequence()186         private Sequence() {
187         }
188 
189         @Override
match(String input, Position p)190         public boolean match(String input, Position p) {
191             int originalIndex = p.index;
192             for (int i = 0; i < items.length; ++i) {
193                 if (!items[i].match(input, p)) {
194                     p.index = originalIndex;
195                     return false;
196                 }
197             }
198             return true;
199         }
200     }
201 
checkName(String nameStr, Set alreadySeen)202     String checkName(String nameStr, Set alreadySeen) {
203         if (nameStr == null) return "";
204         if (alreadySeen.contains(nameStr)) return nameStr;
205         alreadySeen.add(nameStr);
206         return "{" + nameStr + "=}";
207     }
208 
209     public static class Alternation extends ListPick {
210         private WeightedIndex weightedIndex = new WeightedIndex(0);
211 
or2(Pick[] newItems)212         public Alternation or2(Pick[] newItems) {
213             return or2(1, newItems);
214         }
215 
or2(int itemWeight, Pick item)216         public Alternation or2(int itemWeight, Pick item) {
217             return or2(itemWeight, new Pick[] { item }); // we don't care about perf
218         }
219 
or2(int itemWeight, Pick[] newItems)220         public Alternation or2(int itemWeight, Pick[] newItems) {
221             int[] itemWeights = new int[newItems.length];
222             Arrays.fill(itemWeights, itemWeight);
223             return or2(itemWeights, newItems); // we don't care about perf
224         }
225 
or2(int[] itemWeights, Pick[] newItems)226         public Alternation or2(int[] itemWeights, Pick[] newItems) {
227             if (newItems.length != itemWeights.length) {
228                 throw new ArrayIndexOutOfBoundsException(
229                     "or lengths must be equal: " + newItems.length + " != " + itemWeights.length);
230             }
231             // int lastLen = this.items.length;
232             addInternal(newItems);
233             weightedIndex.add(itemWeights);
234             return this; // for chaining
235         }
236 
237         @Override
addTo(Target target)238         protected void addTo(Target target) {
239             items[weightedIndex.toIndex(target.nextDouble())].addTo(target);
240         }
241 
242         @Override
getInternal(int depth, Set alreadySeen)243         public String getInternal(int depth, Set alreadySeen) {
244             String result = checkName(name, alreadySeen);
245             if (result.startsWith("$")) return result;
246             result = indent(depth) + result + "OR(";
247             for (int i = 0; i < items.length; ++i) {
248                 if (i != 0) result += ", ";
249                 result += items[i].getInternal(depth + 1, alreadySeen) + "/" + weightedIndex.weights[i];
250             }
251             return result + ")";
252         }
253 
254         // keep private
Alternation()255         private Alternation() {
256         }
257 
258         // take first matching option
259         @Override
match(String input, Position p)260         public boolean match(String input, Position p) {
261             for (int i = 0; i < weightedIndex.weights.length; ++i) {
262                 if (p.isFailure(this, i)) continue;
263                 if (items[i].match(input, p)) return true;
264                 p.setFailure(this, i);
265             }
266             return false;
267         }
268     }
269 
indent(int depth)270     private static String indent(int depth) {
271         String result = "\r\n";
272         for (int i = 0; i < depth; ++i) {
273             result += " ";
274         }
275         return result;
276     }
277 
278     private static class Repeat extends ItemPick {
279         WeightedIndex weightedIndex;
280         int minCount = 0;
281 
Repeat(int minCount, int maxCount, int[] itemWeights, Pick item)282         private Repeat(int minCount, int maxCount, int[] itemWeights, Pick item) {
283             super(item);
284             weightedIndex = new WeightedIndex(minCount).add(maxCount - minCount + 1, itemWeights);
285         }
286 
287         /*private Repeat(int minCount, int maxCount, int itemWeight, Pick item) {
288             super(item);
289             weightedIndex = new WeightedIndex(minCount).add(maxCount-minCount+1, itemWeight);
290         }*/
291         /*
292         private Repeat(int minCount, int maxCount, Object item) {
293             this.item = convert(item);
294             weightedIndex = new WeightedIndex(minCount).add(maxCount-minCount+1, 1);
295         }
296         */
297         @Override
addTo(Target target)298         protected void addTo(Target target) {
299             //int count ;
300             for (int i = weightedIndex.toIndex(target.nextDouble()); i > 0; --i) {
301                 item.addTo(target);
302             }
303         }
304 
305         @Override
getInternal(int depth, Set alreadySeen)306         public String getInternal(int depth, Set alreadySeen) {
307             String result = checkName(name, alreadySeen);
308             if (result.startsWith("$")) return result;
309             result = indent(depth) + result + "REPEAT(" + weightedIndex
310                 + "; " + item.getInternal(depth + 1, alreadySeen)
311                 + ")";
312             return result;
313         }
314 
315         // match longest, e.g. up to just before a failure
316         @Override
match(String input, Position p)317         public boolean match(String input, Position p) {
318             //int bestMatch = p.index;
319             int count = 0;
320             for (int i = 0; i < weightedIndex.weights.length; ++i) {
321                 if (p.isFailure(this, i)) break;
322                 if (!item.match(input, p)) {
323                     p.setFailure(this, i);
324                     break;
325                 }
326                 //bestMatch = p.index;
327                 count++;
328             }
329             if (count >= minCount) {
330                 return true;
331             }
332             // TODO fix failure
333             return false;
334         }
335     }
336 
337     private static class CodePoint extends FinalPick {
338         private UnicodeSet source;
339 
CodePoint(UnicodeSet source)340         private CodePoint(UnicodeSet source) {
341             this.source = source;
342         }
343 
344         @Override
addTo(Target target)345         protected void addTo(Target target) {
346             target.append(source.charAt(pick(target.random, 0, source.size() - 1)));
347         }
348 
349         @Override
match(String s, Position p)350         public boolean match(String s, Position p) {
351             int cp = UTF16.charAt(s, p.index);
352             if (source.contains(cp)) {
353                 p.index += UTF16.getCharCount(cp);
354                 return true;
355             }
356             p.setMax("codePoint");
357             return false;
358         }
359 
360         @Override
getInternal(int depth, Set alreadySeen)361         public String getInternal(int depth, Set alreadySeen) {
362             String result = checkName(name, alreadySeen);
363             if (result.startsWith("$")) return result;
364             return source.toString();
365         }
366     }
367 
368     static class Morph extends ItemPick {
Morph(Pick item)369         Morph(Pick item) {
370             super(item);
371         }
372 
373         private String lastValue = null;
374         private Target addBuffer = Target.make(this, null, new Quoter.RuleQuoter());
375         private StringBuffer mergeBuffer = new StringBuffer();
376 
377         private static final int COPY_NEW = 0, COPY_BOTH = 1, COPY_LAST = 3, SKIP = 4,
378             LEAST_SKIP = 4;
379         // give weights to the above. make sure we delete about the same as we insert
380         private static final WeightedIndex choice = new WeightedIndex(0)
381             .add(new int[] { 10, 10, 100, 10 });
382 
383         @Override
addTo(Target target)384         protected void addTo(Target target) {
385             // get contents into separate buffer
386             addBuffer.copyState(target);
387             addBuffer.clear();
388             item.addTo(addBuffer);
389             String newValue = addBuffer.get();
390             if (DEBUG) System.out.println("Old: " + lastValue + ", New:" + newValue);
391 
392             // if not first one, merge with old
393             if (lastValue != null) {
394                 mergeBuffer.setLength(0);
395                 int lastIndex = 0;
396                 int newIndex = 0;
397                 // the new length is a random value between old and new.
398                 int newLenLimit = pick(target.random, lastValue.length(), newValue.length());
399 
400                 while (mergeBuffer.length() < newLenLimit
401                     && newIndex < newValue.length()
402                     && lastIndex < lastValue.length()) {
403                     int c = choice.toIndex(target.nextDouble());
404                     if (c == COPY_NEW || c == COPY_BOTH || c == SKIP) {
405                         newIndex = getChar(newValue, newIndex, mergeBuffer, c < LEAST_SKIP);
406                         if (mergeBuffer.length() >= newLenLimit) break;
407                     }
408                     if (c == COPY_LAST || c == COPY_BOTH || c == SKIP) {
409                         lastIndex = getChar(lastValue, lastIndex, mergeBuffer, c < LEAST_SKIP);
410                     }
411                 }
412                 newValue = mergeBuffer.toString();
413             }
414             lastValue = newValue;
415             target.append(newValue);
416             if (DEBUG) System.out.println("Result: " + newValue);
417         }
418 
419         @Override
getInternal(int depth, Set alreadySeen)420         public String getInternal(int depth, Set alreadySeen) {
421             String result = checkName(name, alreadySeen);
422             if (result.startsWith("$")) return result;
423             return indent(depth) + result + "MORPH("
424                 + item.getInternal(depth + 1, alreadySeen)
425                 + ")";
426         }
427 
428         /* (non-Javadoc)
429          * @see Pick#match(java.lang.String, Pick.Position)
430          */
431         @Override
match(String input, Position p)432         public boolean match(String input, Position p) {
433             // TODO Auto-generated method stub
434             return false;
435         }
436     }
437 
438     /* Add character if we can
439      */
getChar(String newValue, int newIndex, StringBuffer mergeBuffer, boolean copy)440     static int getChar(String newValue, int newIndex, StringBuffer mergeBuffer, boolean copy) {
441         if (newIndex >= newValue.length()) return newIndex;
442         int cp = UTF16.charAt(newValue, newIndex);
443         if (copy) UTF16.append(mergeBuffer, cp);
444         return newIndex + UTF16.getCharCount(cp);
445     }
446 
447     /*
448             // quoted add
449             appendQuoted(target, addBuffer.toString(), quoteBuffer);
450             // fix buffers
451             StringBuffer swapTemp = addBuffer;
452             addBuffer = source;
453             source = swapTemp;
454         }
455     }
456     */
457 
458     static class Quote extends ItemPick {
Quote(Pick item)459         Quote(Pick item) {
460             super(item);
461         }
462 
463         @Override
addTo(Target target)464         protected void addTo(Target target) {
465             target.quoter.setQuoting(true);
466             item.addTo(target);
467             target.quoter.setQuoting(false);
468         }
469 
470         @Override
match(String s, Position p)471         public boolean match(String s, Position p) {
472             return false;
473         }
474 
475         @Override
getInternal(int depth, Set alreadySeen)476         public String getInternal(int depth, Set alreadySeen) {
477             String result = checkName(name, alreadySeen);
478             if (result.startsWith("$")) return result;
479             return indent(depth) + result + "QUOTE(" + item.getInternal(depth + 1, alreadySeen)
480                 + ")";
481         }
482     }
483 
484     private static class Literal extends FinalPick {
485         @Override
toString()486         public String toString() {
487             return name;
488         }
489 
Literal(String source)490         private Literal(String source) {
491             this.name = source;
492         }
493 
494         @Override
addTo(Target target)495         protected void addTo(Target target) {
496             target.append(name);
497         }
498 
499         @Override
match(String input, Position p)500         public boolean match(String input, Position p) {
501             int len = name.length();
502             if (input.regionMatches(p.index, name, 0, len)) {
503                 p.index += len;
504                 return true;
505             }
506             p.setMax("literal");
507             return false;
508         }
509 
510         @Override
getInternal(int depth, Set alreadySeen)511         public String getInternal(int depth, Set alreadySeen) {
512             return "'" + name + "'";
513         }
514     }
515 
516     public static class Position {
517         public ArrayList failures = new ArrayList();
518         public int index;
519         public int maxInt;
520         public String maxType;
521 
setMax(String type)522         public void setMax(String type) {
523             if (index >= maxInt) {
524                 maxType = type;
525             }
526         }
527 
528         @Override
toString()529         public String toString() {
530             return "index; " + index
531                 + ", maxInt:" + maxInt
532                 + ", maxType: " + maxType;
533         }
534         /*private static final Object BAD = new Object();
535         private static final Object GOOD = new Object();*/
536 
isFailure(Pick pick, int item)537         public boolean isFailure(Pick pick, int item) {
538             ArrayList val = (ArrayList) failures.get(index);
539             if (val == null) return false;
540             Set set = (Set) val.get(item);
541             if (set == null) return false;
542             return !set.contains(pick);
543         }
544 
setFailure(Pick pick, int item)545         public void setFailure(Pick pick, int item) {
546             ArrayList val = (ArrayList) failures.get(index);
547             if (val == null) {
548                 val = new ArrayList();
549                 failures.set(index, val);
550             }
551             Set set = (Set) val.get(item);
552             if (set == null) {
553                 set = new HashSet();
554                 val.set(item, set);
555             }
556             set.add(pick);
557         }
558     }
559 
560     /*
561     public static final Pick NOTHING = new Nothing();
562 
563 
564     private static class Nothing extends FinalPick {
565         protected void addTo(Target target) {}
566         protected boolean match(String input, Position p) {
567             return true;
568         }
569         public String getInternal(int depth, Set alreadySeen) {
570             return indent(depth) + "\u00F8";
571         }
572     }
573     */
574 
575     // intermediates
576 
577     abstract static class Visitor {
578         Set already = new HashSet();
579 
580         // Note: each visitor should return the Pick that will replace a (or a itself)
handle(Pick a)581         abstract Pick handle(Pick a);
582 
alreadyEntered(Pick item)583         boolean alreadyEntered(Pick item) {
584             boolean result = already.contains(item);
585             already.add(item);
586             return result;
587         }
588 
reset()589         void reset() {
590             already.clear();
591         }
592     }
593 
visit(Visitor visitor)594     protected abstract Pick visit(Visitor visitor);
595 
596     static class Replacer extends Visitor {
597         String toReplace;
598         Pick replacement;
599 
Replacer(String toReplace, Pick replacement)600         Replacer(String toReplace, Pick replacement) {
601             this.toReplace = toReplace;
602             this.replacement = replacement;
603         }
604 
605         @Override
handle(Pick a)606         public Pick handle(Pick a) {
607             if (toReplace.equals(a.name)) {
608                 a = replacement;
609             }
610             return a;
611         }
612     }
613 
614     abstract private static class FinalPick extends Pick {
615         @Override
visit(Visitor visitor)616         public Pick visit(Visitor visitor) {
617             return visitor.handle(this);
618         }
619     }
620 
621     private abstract static class ItemPick extends Pick {
622         protected Pick item;
623 
ItemPick(Pick item)624         ItemPick(Pick item) {
625             this.item = item;
626         }
627 
628         @Override
visit(Visitor visitor)629         public Pick visit(Visitor visitor) {
630             Pick result = visitor.handle(this);
631             if (visitor.alreadyEntered(this)) return result;
632             if (item != null) item = item.visit(visitor);
633             return result;
634         }
635     }
636 
637     private abstract static class ListPick extends Pick {
638         protected Pick[] items = new Pick[0];
639 
simplify()640         Pick simplify() {
641             if (items.length > 1) return this;
642             if (items.length == 1) return items[0];
643             return null;
644         }
645 
size()646         int size() {
647             return items.length;
648         }
649 
getLast()650         Pick getLast() {
651             return items[items.length - 1];
652         }
653 
setLast(Pick newOne)654         void setLast(Pick newOne) {
655             items[items.length - 1] = newOne;
656         }
657 
addInternal(Pick[] objs)658         protected void addInternal(Pick[] objs) {
659             int lastLen = items.length;
660             items = realloc(items, items.length + objs.length);
661             for (int i = 0; i < objs.length; ++i) {
662                 items[lastLen + i] = objs[i];
663             }
664         }
665 
666         @Override
visit(Visitor visitor)667         public Pick visit(Visitor visitor) {
668             Pick result = visitor.handle(this);
669             if (visitor.alreadyEntered(this)) return result;
670             for (int i = 0; i < items.length; ++i) {
671                 items[i] = items[i].visit(visitor);
672             }
673             return result;
674         }
675     }
676 
677     /**
678      * Simple class to distribute a number between 0 (inclusive) and 1 (exclusive) among
679      * a number of indices, where each index is weighted.
680      * Item weights may be zero, but cannot be negative.
681      * @author Davis
682      */
683     // As in other case, we use an array for runtime speed; don't care about buildspeed.
684     public static class WeightedIndex {
685         private int[] weights = new int[0];
686         private int minCount = 0;
687         private double total;
688 
WeightedIndex(int minCount)689         public WeightedIndex(int minCount) {
690             this.minCount = minCount;
691         }
692 
add(int count, int itemWeights)693         public WeightedIndex add(int count, int itemWeights) {
694             if (count > 0) {
695                 int[] newWeights = new int[count];
696                 if (itemWeights < 1) itemWeights = 1;
697                 Arrays.fill(newWeights, 0, count, itemWeights);
698                 add(1, newWeights);
699             }
700             return this; // for chaining
701         }
702 
add(int[] newWeights)703         public WeightedIndex add(int[] newWeights) {
704             return add(newWeights.length, newWeights);
705         }
706 
add(int maxCount, int[] newWeights)707         public WeightedIndex add(int maxCount, int[] newWeights) {
708             if (newWeights == null) newWeights = new int[] { 1 };
709             int oldLen = weights.length;
710             if (maxCount < newWeights.length) maxCount = newWeights.length;
711             weights = realloc(weights, weights.length + maxCount);
712             System.arraycopy(newWeights, 0, weights, oldLen, newWeights.length);
713             int lastWeight = weights[oldLen + newWeights.length - 1];
714             for (int i = oldLen + newWeights.length; i < maxCount; ++i) {
715                 weights[i] = lastWeight;
716             }
717             total = 0;
718             for (int i = 0; i < weights.length; ++i) {
719                 if (weights[i] < 0) {
720                     throw new RuntimeException("only positive weights: " + i);
721                 }
722                 total += weights[i];
723             }
724             return this; // for chaining
725         }
726 
727         // TODO, make this more efficient
toIndex(double zeroToOne)728         public int toIndex(double zeroToOne) {
729             double weight = zeroToOne * total;
730             int i;
731             for (i = 0; i < weights.length; ++i) {
732                 weight -= weights[i];
733                 if (weight <= 0) break;
734             }
735             return i + minCount;
736         }
737 
738         @Override
toString()739         public String toString() {
740             String result = "";
741             for (int i = 0; i < minCount; ++i) {
742                 if (result.length() != 0) result += ",";
743                 result += "0";
744             }
745             for (int i = 0; i < weights.length; ++i) {
746                 if (result.length() != 0) result += ",";
747                 result += weights[i];
748             }
749             return result;
750         }
751     }
752     /*
753     private static Pick convert(Object obj) {
754         if (obj instanceof Pick) return (Pick)obj;
755         return new Literal(obj.toString(), false);
756     }
757     */
758     // Useful statics
759 
pick(Random random, int start, int end)760     static public int pick(Random random, int start, int end) {
761         return start + (int) (random.nextDouble() * (end + 1 - start));
762     }
763 
pick(Random random, double start, double end)764     static public double pick(Random random, double start, double end) {
765         return start + (random.nextDouble() * (end + 1 - start));
766     }
767 
pick(Random random, double percent)768     static public boolean pick(Random random, double percent) {
769         return random.nextDouble() <= percent;
770     }
771 
pick(Random random, UnicodeSet s)772     static public int pick(Random random, UnicodeSet s) {
773         return s.charAt(pick(random, 0, s.size() - 1));
774     }
775 
pick(Random random, String[] source)776     static public String pick(Random random, String[] source) {
777         return source[pick(random, 0, source.length - 1)];
778     }
779 
780     // these utilities really ought to be in Java
781 
realloc(double[] source, int newSize)782     public static double[] realloc(double[] source, int newSize) {
783         double[] temp = new double[newSize];
784         if (newSize > source.length) newSize = source.length;
785         if (newSize != 0) System.arraycopy(source, 0, temp, 0, newSize);
786         return temp;
787     }
788 
realloc(int[] source, int newSize)789     public static int[] realloc(int[] source, int newSize) {
790         int[] temp = new int[newSize];
791         if (newSize > source.length) newSize = source.length;
792         if (newSize != 0) System.arraycopy(source, 0, temp, 0, newSize);
793         return temp;
794     }
795 
realloc(Pick[] source, int newSize)796     public static Pick[] realloc(Pick[] source, int newSize) {
797         Pick[] temp = new Pick[newSize];
798         if (newSize > source.length) newSize = source.length;
799         if (newSize != 0) System.arraycopy(source, 0, temp, 0, newSize);
800         return temp;
801     }
802 
803     // test utilities
804     /*private static void append(StringBuffer target, String toAdd, StringBuffer quoteBuffer) {
805         Utility.appendToRule(target, (int)-1, true, false, quoteBuffer); // close previous quote
806         if (DEBUG) System.out.println("\"" + toAdd + "\"");
807         target.append(toAdd);
808     }
809 
810     private static void appendQuoted(StringBuffer target, String toAdd, StringBuffer quoteBuffer) {
811         if (DEBUG) System.out.println("\"" + toAdd + "\"");
812         Utility.appendToRule(target, toAdd, false, false, quoteBuffer);
813     }*/
814 
815     /*
816     public static abstract class MatchHandler {
817         public abstract void handleString(String source, int start, int limit);
818         public abstract void handleSequence(String source, int start, int limit);
819         public abstract void handleAlternation(String source, int start, int limit);
820 
821     }
822     */
823     /*
824     // redistributes random value
825     // values are still between 0 and 1, but with a different distribution
826     public interface Spread {
827         public double spread(double value);
828     }
829 
830     // give the weight for the high end.
831     // values are linearly scaled according to the weight.
832     static public class SimpleSpread implements Spread {
833         static final Spread FLAT = new SimpleSpread(1.0);
834         boolean flat = false;
835         double aa, bb, cc;
836         public SimpleSpread(double maxWeight) {
837             if (maxWeight > 0.999 && maxWeight < 1.001) {
838                 flat = true;
839             } else {
840                 double q = (maxWeight - 1.0);
841                 aa = -1/q;
842                 bb = 1/(q*q);
843                 cc = (2.0+q)/q;
844            }
845         }
846         public double spread(double value) {
847             if (flat) return value;
848             value = aa + Math.sqrt(bb + cc*value);
849             if (value < 0.0) return 0.0;    // catch math gorp
850             if (value >= 1.0) return 1.0;
851             return value;
852         }
853     }
854     static public int pick(Spread spread, Random random, int start, int end) {
855         return start + (int)(spread.spread(random.nextDouble()) * (end + 1 - start));
856     }
857 
858     */
859 
860 }