import java.util.*; import java.util.zip.*; import java.util.List; import java.util.regex.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.concurrent.locks.*; import java.util.function.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; import javax.swing.table.*; import java.io.*; import java.net.*; import java.lang.reflect.*; import java.lang.ref.*; import java.lang.management.*; import java.security.*; import java.security.spec.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.awt.geom.*; import javax.imageio.*; import java.math.*; import static x30_pkg.x30_util.DynamicObject; class main { static class EnglishDateParser extends DateStructures { boolean assumeFuture = true; // e.g. for "tuesday" [not used] List tok; int maxTokens = 3; // "top dogs" are the longest non-overlapping parses List> topDogs(String s) { return pwt_topDogs(pwt_filterByType(SomeDate.class, allParses(s))); } SomeDate parse(String s) { return getVar(first(topDogs(s))); } IterableIterator allParses(String s) { // tokenize, initialize List> initials = pwt_initial(tok = javaTok(s), maxTokens); List out = new ArrayList(); // find numbers List> numbers = pwt_transform(number(), initials); // find ordinals (1st, 2nd, ...) List> ordinals = new ArrayList(); for (ParsedWithTokens number : numbers) for (ParsedWithTokens ord : parseToTheRight(fixedToken("st", "nd", "rd", "th"), number)) ordinals.add(pwt_combine(number, ord)); //print(+ordinals); // "in days" for (ParsedWithTokens number : numbers) for (ParsedWithTokens in : parseToTheLeft(fixedToken("in"), number)) for (ParsedWithTokens days : parseToTheRight(fixedToken("day", "days"), number)) out.add(pwt_combine(new TodayPlus(number.get()), in, days)); // " days from now" for (ParsedWithTokens number : numbers) for (ParsedWithTokens daysFromNow : parseToTheRight(fixedToken("day from now", "days from now"), number)) out.add(pwt_combine(new TodayPlus(number.get()), number, daysFromNow)); List> years = pwt_filter(__17 -> isYear(__17), numbers); out.addAll(years); List> months = pwt_filter(__18 -> isMonthNr(__18), numbers); List> dayOfMonths = pwt_filter(__19 -> isDayOfMonth(__19), numbers); List> weekdays = pwt_transform(weekday(), initials); out.addAll(weekdays); // month names List> monthNames = pwt_transform(monthName(), initials); out.addAll(monthNames); // month name + year, e.g. "February 2020" out.addAll(pwt_combine(monthNames, years, (month, year) -> new Month(month.month, new Year(year)))); // month name + ordinal, e.g. "March 4th" out.addAll(pwt_combine(monthNames, ordinals, (month, ord) -> new Day(ord, month))); // yesterday, today, tomorrow out.addAll(pwt_transform(t -> eqic(t, "yesterday") ? new TodayPlus(-1) : eqic(t, "today") ? new TodayPlus(0) : new TodayPlus(1), pwt_transform(fixedToken("yesterday", "today", "tomorrow"), initials))); // last/this/next week for (ParsedWithTokens week : pwt_transform(fixedToken("week"), initials)) for (ParsedWithTokens which : parseToTheLeft(fixedToken("last", "this", "next"), week)) out.add(pwt_combine(new CurrentWeekPlus( eqic(which.get(), "last") ? -1 : eqic(which.get(), "this") ? 0 : 1), which, week)); // "next " for (ParsedWithTokens weekday : weekdays) for (ParsedWithTokens next : parseToTheLeft(fixedToken("next"), weekday)) out.add(pwt_combine(new Weekday(weekday.get().weekday, new CurrentWeekPlus(1)), next, weekday)); for (ParsedWithTokens year : years) for (ParsedWithTokens slash : parseToTheRight(fixedToken("/"), year)) for (ParsedWithTokens month : pwt_toTheRightOf(months, slash)) for (ParsedWithTokens slash2 : parseToTheRight(fixedToken("/"), month)) for (ParsedWithTokens day : pwt_toTheRightOf(dayOfMonths, slash2)) out.add(pwt_combine(new Day(day.get(), new Month(month.get(), new Year(year.get()))), year, day)); List> hours = pwt_transform(__20 -> numberToHour(__20), numbers); List> minutes = pwt_filter(__21 -> isMinute(__21), numbers); List> seconds = minutes; List> colons = pwt_filter(t -> eq(t, ":"), initials); // 15:12 etc. List> hoursAndMinutes = pwt_combine(hours, colons, minutes, (h, __, m) -> new Minute(m, h)); out.addAll(hoursAndMinutes); List> hoursAndMinutesAndSeconds = pwt_combine(hoursAndMinutes, colons, seconds, (hm, __, second) -> new Second(second, hm)); out.addAll(hoursAndMinutesAndSeconds); List> amPMs = pwt_transform(fixedToken("am", "pm"), initials); // 3 am, 5 pm etc. List> amPMTimes = pwt_combine(numbers, amPMs, (hour, amPM) -> !between(hour, 1, 12) ? null : new Hour(hour, eqic(amPM, "pm"))); out.addAll(amPMTimes); // between 1 and 2 pm for (ParsedWithTokens time : amPMTimes) for (ParsedWithTokens and : parseToTheLeft(fixedToken("and"), time)) for (ParsedWithTokens hour : pwt_toTheLeftOf(hours, and)) out.add(pwt_combine(new Between(new Hour(hour.get().hour, time.get().isPM), time.get()), time, hour)); return itIt(out); } IF1 number() { return s -> isInteger(s) ? parseInt(s) : null; } boolean isYear(int n) { return between(n, 1900, 2100); } boolean isMonthNr(int n) { return between(n, 1, 12); } boolean isDayOfMonth(int n) { return between(n, 1, 31); } boolean isHour(int n) { return between(n, 0, 23); } boolean isMinute(int n) { return between(n, 0, 59); } boolean isSecond(int n) { return between(n, 0, 59); } Hour numberToHour(int n) { return !isHour(n) ? null : n > 12 ? new Hour(n-12, true) : new Hour(n, null); } IF1 fixedToken(String... tokens) { return fixedToken(litciset(tokens)); } IF1 fixedToken(Set set) { return t -> contains(set, t) ? t : null; } IF1 weekday() { return s -> { int n = parseEnglishWeekday(s); return n == 0 ? null : new Weekday(n); }; } IF1 monthName() { return s -> { int n = parseEnglishMonthName(s); return n == 0 ? null : new Month(n); }; } List> parseToTheLeft(IF1 f, ParsedWithTokens p) { return pwt_transform(f, pwt_precedingTokens(1, maxTokens, p.start())); } List> parseToTheRight(IF1 f, ParsedWithTokens p) { return pwt_transform(f, pwt_followingTokens(1, maxTokens, p.remaining())); } } static List> pwt_topDogs(Iterable> l) { List> topDogs = new ArrayList(); for (ParsedWithTokens p : unnullForIteration(l)) for (int i = p.iStart; i < p.iRemaining; i += 2) listPut(topDogs, i, pwt_winner(_get(topDogs, i), p)); return uniquify(nonNulls(topDogs)); } static List> pwt_filterByType(Class type, Iterable l) { return (List) filter(l, p -> isInstance(type, p.get())); } static A getVar(IF0 v) { return v == null ? null : v.get(); } static A getVar(Optional v) { return v == null ? null : v.orElse(null); } static Object first(Object list) { return first((Iterable) list); } static A first(List list) { return empty(list) ? null : list.get(0); } static A first(A[] bla) { return bla == null || bla.length == 0 ? null : bla[0]; } static Pair first(Map map) { return mapEntryToPair(first(entrySet(map))); } static Pair first(MultiMap mm) { if (mm == null) return null; var e = first(mm.data.entrySet()); if (e == null) return null; return pair(e.getKey(), first(e.getValue())); } static A first(IterableIterator i) { return first((Iterator) i); } static A first(Iterator i) { return i == null || !i.hasNext() ? null : i.next(); } static A first(Iterable i) { if (i == null) return null; Iterator it = i.iterator(); return it.hasNext() ? it.next() : null; } static Character first(String s) { return empty(s) ? null : s.charAt(0); } static Character first(CharSequence s) { return empty(s) ? null : s.charAt(0); } static A first(Pair p) { return p == null ? null : p.a; } static Byte first(byte[] l) { return empty(l) ? null : l[0]; } static A first(A[] l, IF1 pred) { return firstThat(l, pred); } static A first(Iterable l, IF1 pred) { return firstThat(l, pred); } static A first(IF1 pred, Iterable l) { return firstThat(pred, l); } static List> pwt_initial(int maxTokens, String s) { return pwt_initial(s, maxTokens); } static List> pwt_initial(String s, int maxTokens) { return pwt_initial(javaTok(s), maxTokens); } // maxTokens = how many code tokens per range (max) static List> pwt_initial(List tok, int maxTokens) { return concatMap(lai_codeTokens(tok), lai -> pwt_followingTokens(1, maxTokens, lai)); } static List> pwt_initial(int maxTokens, List tok) { return pwt_initial(tok, maxTokens); } // TODO: extended multi-line strings static int javaTok_n, javaTok_elements; static boolean javaTok_opt = false; static List javaTok(String s) { ++javaTok_n; ArrayList tok = new ArrayList(); int l = s == null ? 0 : s.length(); int i = 0; while (i < l) { int j = i; char c, d; // scan for whitespace while (j < l) { c = s.charAt(j); d = j+1 >= l ? '\0' : s.charAt(j+1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !regionMatches(s, j, "*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } tok.add(javaTok_substringN(s, i, j)); i = j; if (i >= l) break; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace // Special JavaX syntax: 'identifier if (c == '\'' && Character.isJavaIdentifierStart(d) && i+2 < l && "'\\".indexOf(s.charAt(i+2)) < 0) { j += 2; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))) ++j; } else if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { int c2 = s.charAt(j); if (c2 == opener || c2 == '\n' && opener == '\'') { // allow multi-line strings, but not for ' ++j; break; } else if (c2 == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\'')); // for stuff like "don't" else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L } else if (c == '[' && d == '[') { do ++j; while (j < l && !regionMatches(s, j, "]]")); j = Math.min(j+2, l); } else if (c == '[' && d == '=' && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !regionMatches(s, j, "]=]")); j = Math.min(j+3, l); } else ++j; tok.add(javaTok_substringC(s, i, j)); i = j; } if ((tok.size() % 2) == 0) tok.add(""); javaTok_elements += tok.size(); return tok; } static List javaTok(List tok) { return javaTokWithExisting(join(tok), tok); } static List> pwt_transform(IF1 f, Iterable> l) { return map_nonNulls(p -> { B b = f.get(p.get()); return b == null ? null : p.withValue(b); }, l); } static ParsedWithTokens pwt_combine(A value, ParsedWithTokens p1, ParsedWithTokens p2) { assertSame(p1.tok, p2.tok); return new ParsedWithTokens(value, p1.tok, min(p1.iStart, p2.iStart), max(p1.iRemaining, p2.iRemaining)); } // shorter version taking value of first pwt static ParsedWithTokens pwt_combine(ParsedWithTokens p1, ParsedWithTokens p2) { return pwt_combine(p1.get(), p1, p2); } // entirely different meaning static List> pwt_combine(Iterable> l1, Iterable> l2, IF2 f) { List> out = new ArrayList(); for (ParsedWithTokens a : l1) for (ParsedWithTokens b : pwt_toTheRightOf(l2, a)) out.add(pwt_combine(f.get(a.get(), b.get()), a, b)); return out; } static List> pwt_combine(Iterable> l1, Iterable> l2, Iterable> l3, IF3 f) { List> out = new ArrayList(); for (ParsedWithTokens a : l1) for (ParsedWithTokens b : pwt_toTheRightOf(l2, a)) for (ParsedWithTokens c : pwt_toTheRightOf(l3, b)) out.add(pwt_combine(f.get(a.get(), b.get(), c.get()), a, c)); return out; } static List> pwt_filter(IF1 f, Iterable> l) { return filter(p -> f.get(p.get()), l); } static String weekday() { return get(englishWeekdays(), dayOfWeek_nr()-1); } static boolean eqic(String a, String b) { if ((a == null) != (b == null)) return false; if (a == null) return true; return a.equalsIgnoreCase(b); } static boolean eqic(Symbol a, Symbol b) { return eq(a, b); } static boolean eqic(Symbol a, String b) { return eqic(asString(a), b); } static boolean eqic(char a, char b) { if (a == b) return true; char u1 = Character.toUpperCase(a); char u2 = Character.toUpperCase(b); if (u1 == u2) return true; return Character.toLowerCase(u1) == Character.toLowerCase(u2); } static IterableIterator> pwt_toTheRightOf(Iterable> l, ParsedWithTokens b) { return filterI(iterator(l), p -> { //print("ttro: " + p.iStart + " / " + b.iRemaining); return p.iStart == (b.iRemaining | 1); }); } static boolean eq(Object a, Object b) { return a == b || a != null && b != null && a.equals(b); } // a little kludge for stuff like eq(symbol, "$X") static boolean eq(Symbol a, String b) { return eq(str(a), b); } static boolean between(long x, long min, long max) { return isBetween(x, min, max); } static boolean between(double x, double min, double max) { return isBetween(x, min, max); } static IterableIterator> pwt_toTheLeftOf(Iterable> l, ParsedWithTokens b) { return filterI(iterator(l), p -> { //print("ttlo: " + p.iRemaining + " / " + b.iStart); return (p.iRemaining | 1) == (b.iStart | 1); }); } static IterableIterator itIt(Iterable l) { if (l == null) return emptyItIt(); if (l instanceof IterableIterator) return ((IterableIterator) l); Iterator it = l.iterator(); if (it instanceof IterableIterator) return ((IterableIterator) it); return new IterableIterator() { public boolean hasNext() { return it.hasNext(); } public A next() { return it.next(); } }; } static boolean isInteger(String s) { int n = l(s); if (n == 0) return false; int i = 0; if (s.charAt(0) == '-') if (++i >= n) return false; while (i < n) { char c = s.charAt(i); if (c < '0' || c > '9') return false; ++i; } return true; } static int parseInt(String s) { return emptyString(s) ? 0 : Integer.parseInt(s); } static int parseInt(char c) { return Integer.parseInt(str(c)); } static TreeSet litciset(String... items) { TreeSet set = caseInsensitiveSet(); for (String a : items) set.add(a); return set; } static TreeSet litciset(Symbol... items) { TreeSet set = treeSet(); // HashSet would also do, but we might have the return type fixed somewhere, and they might want a NavigableMap. for (Symbol a : items) set.add(a); return set; } static boolean contains(Collection c, Object o) { return c != null && c.contains(o); } static boolean contains(Iterable it, Object a) { if (it != null) for (Object o : it) if (eq(a, o)) return true; return false; } static boolean contains(Object[] x, Object o) { if (x != null) for (Object a : x) if (eq(a, o)) return true; return false; } static boolean contains(String s, char c) { return s != null && s.indexOf(c) >= 0; } static boolean contains(String s, String b) { return s != null && s.indexOf(b) >= 0; } static boolean contains(BitSet bs, int i) { return bs != null && bs.get(i); } static int parseEnglishWeekday(String s) { return indexOfIC(englishWeekdays(), s)+1; } static Map parseEnglishMonthName_cache; // returns 1-12 (or 0 if unknown) static int parseEnglishMonthName(String s) { if (parseEnglishMonthName_cache == null) parseEnglishMonthName_cache = listIndexCI(englishMonthNames()); return or(parseEnglishMonthName_cache.get(s), -1)+1; } static IterableIterator> pwt_precedingTokens(int minTokens, int maxTokens, ListAndIndex tok) { int remaining = countPrecedingTokens(tok); int iStart = tok.idx; return countIterator_inclusive( min(minTokens, remaining), min(maxTokens, remaining), n -> pwt_raw(tok.list, iStart-n*2, iStart-1)); } static IterableIterator> pwt_followingTokens(int minTokens, int maxTokens, ListAndIndex tok) { int remaining = countRemainingTokens(tok); int iStart = tok.idx | 1; // go to C token return countIterator_inclusive( min(minTokens, remaining), min(maxTokens, remaining), n -> pwt_raw(tok.list, iStart, iStart+n*2-1)); } static String unnullForIteration(String s) { return s == null ? "" : s; } static Collection unnullForIteration(Collection l) { return l == null ? immutableEmptyList() : l; } static List unnullForIteration(List l) { return l == null ? immutableEmptyList() : l; } static int[] unnullForIteration(int[] l) { return l == null ? emptyIntArray() : l; } static char[] unnullForIteration(char[] l) { return l == null ? emptyCharArray() : l; } static double[] unnullForIteration(double[] l) { return l == null ? emptyDoubleArray() : l; } static short[] unnullForIteration(short[] l) { return l == null ? emptyShortArray() : l; } static Map unnullForIteration(Map l) { return l == null ? immutableEmptyMap() : l; } static Iterable unnullForIteration(Iterable i) { return i == null ? immutableEmptyList() : i; } static A[] unnullForIteration(A[] a) { return a == null ? (A[]) emptyObjectArray() : a; } static BitSet unnullForIteration(BitSet b) { return b == null ? new BitSet() : b; } //ifclass Symbol static Symbol unnullForIteration(Symbol s) { return s == null ? emptySymbol() : s; } //endif static Pair unnullForIteration(Pair p) { return p != null ? p : new Pair(null, null); } static long unnullForIteration(Long l) { return l == null ? 0L : l; } static void listPut(List l, int i, A a, A emptyElement) { listSet(l, i, a, emptyElement); } static void listPut(List l, int i, A a) { listSet(l, i, a); } static ParsedWithTokens pwt_winner(ParsedWithTokens a, ParsedWithTokens b) { return a == null ? b : b == null ? a : a.length() >= b.length() ? a : b; } static A _get(List l, int idx) { return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null; } static Object _get(Object o, String field) { return get(o, field); } static Object _get(String field, Object o) { return get(o, field); } static A _get(A[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : null; } static List uniquify(Collection l) { return uniquifyList(l); } static List nonNulls(Iterable l) { return withoutNulls(l); } static List nonNulls(A[] l) { return withoutNulls(l); } static Map nonNulls(Map map) { return withoutNulls(map); } static List filter(Iterable c, Object pred) { if (pred instanceof F1) return filter(c, (F1) pred); List x = new ArrayList(); if (c != null) for (Object o : c) if (isTrue(callF(pred, o))) x.add(o); return x; } static List filter(Object pred, Iterable c) { return filter(c, pred); } static List filter(Iterable c, F1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static List filter(F1 pred, Iterable c) { return filter(c, pred); } //ifclass IF1 static List filter(Iterable c, IF1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static List filter(B[] c, IF1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static List filter(IF1 pred, Iterable c) { return filter(c, pred); } //endif static boolean isInstance(Class type, Object arg) { return type.isInstance(arg); } static boolean empty(Collection c) { return c == null || c.isEmpty(); } static boolean empty(Iterable c) { return c == null || !c.iterator().hasNext(); } static boolean empty(CharSequence s) { return s == null || s.length() == 0; } static boolean empty(Map map) { return map == null || map.isEmpty(); } static boolean empty(Object[] o) { return o == null || o.length == 0; } static boolean empty(BitSet bs) { return bs == null || bs.isEmpty(); } static boolean empty(Object o) { if (o instanceof Collection) return empty((Collection) o); if (o instanceof String) return empty((String) o); if (o instanceof Map) return empty((Map) o); if (o instanceof Object[]) return empty((Object[]) o); if (o instanceof byte[]) return empty((byte[]) o); if (o == null) return true; throw fail("unknown type for 'empty': " + getType(o)); } static boolean empty(Iterator i) { return i == null || !i.hasNext(); } static boolean empty(double[] a) { return a == null || a.length == 0; } static boolean empty(float[] a) { return a == null || a.length == 0; } static boolean empty(int[] a) { return a == null || a.length == 0; } static boolean empty(long[] a) { return a == null || a.length == 0; } static boolean empty(byte[] a) { return a == null || a.length == 0; } static boolean empty(short[] a) { return a == null || a.length == 0; } static boolean empty(MultiMap mm) { return mm == null || mm.isEmpty(); } static boolean empty(File f) { return getFileSize(f) == 0; } static Pair mapEntryToPair(Map.Entry e) { return e == null ? null : pair(e.getKey(), e.getValue()); } static Set> entrySet(Map map) { return _entrySet(map); } static Pair pair(A a, B b) { return new Pair(a, b); } static Pair pair(A a) { return new Pair(a, a); } static A firstThat(Iterable l, IF1 pred) { for (A a : unnullForIteration(l)) if (pred.get(a)) return a; return null; } static A firstThat(A[] l, IF1 pred) { for (A a : unnullForIteration(l)) if (pred.get(a)) return a; return null; } static A firstThat(IF1 pred, Iterable l) { return firstThat(l, pred); } static A firstThat(IF1 pred, A[] l) { return firstThat(l, pred); } // f must return a list static List concatMap(Object f, Iterable l) { return concatLists(map(f, l)); } static List concatMap(Iterable l, Object f) { return concatMap(f, l); } static List concatMap(Object f, Object[] l) { return concatLists(map(f, l)); } static List concatMap(Object[] l, Object f) { return concatMap(f, l); } static > List concatMap(Iterable l, IF1 f) { return concatMap(l, (Object) f); } static > List concatMap(IF1 f, Iterable l) { return concatMap(l, f); } static > List concatMap(IF1 f, A[] l) { return concatMap((Object) f, l); } static List> lai_codeTokens(List tok) { return map(codeTokenIndices(tok), i -> new ListAndIndex(tok, i)); } static boolean regionMatches(String a, int offsetA, String b, int offsetB, int len) { return a != null && b != null && a.regionMatches(offsetA, b, offsetB, len); } static boolean regionMatches(String a, int offsetA, String b) { return regionMatches(a, offsetA, b, 0, l(b)); } static String javaTok_substringN(String s, int i, int j) { if (i == j) return ""; if (j == i+1 && s.charAt(i) == ' ') return " "; return s.substring(i, j); } static String javaTok_substringC(String s, int i, int j) { return s.substring(i, j); } static List javaTokWithExisting(String s, List existing) { ++javaTok_n; int nExisting = javaTok_opt && existing != null ? existing.size() : 0; ArrayList tok = existing != null ? new ArrayList(nExisting) : new ArrayList(); int l = s.length(); int i = 0, n = 0; while (i < l) { int j = i; char c, d; // scan for whitespace while (j < l) { c = s.charAt(j); d = j+1 >= l ? '\0' : s.charAt(j+1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } if (n < nExisting && javaTokWithExisting_isCopyable(existing.get(n), s, i, j)) tok.add(existing.get(n)); else tok.add(javaTok_substringN(s, i, j)); ++n; i = j; if (i >= l) break; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace // Special JavaX syntax: 'identifier if (c == '\'' && Character.isJavaIdentifierStart(d) && i+2 < l && "'\\".indexOf(s.charAt(i+2)) < 0) { j += 2; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))) ++j; } else if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener /*|| s.charAt(j) == '\n'*/) { // allow multi-line strings ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // for stuff like "don't" else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L } else if (c == '[' && d == '[') { do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else if (c == '[' && d == '=' && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); j = Math.min(j+3, l); } else ++j; if (n < nExisting && javaTokWithExisting_isCopyable(existing.get(n), s, i, j)) tok.add(existing.get(n)); else tok.add(javaTok_substringC(s, i, j)); ++n; i = j; } if ((tok.size() % 2) == 0) tok.add(""); javaTok_elements += tok.size(); return tok; } static boolean javaTokWithExisting_isCopyable(String t, String s, int i, int j) { return t.length() == j-i && s.regionMatches(i, t, 0, j-i); // << could be left out, but that's brave } public static String join(String glue, Iterable strings) { if (strings == null) return ""; if (strings instanceof Collection) { if (((Collection) strings).size() == 1) return str(first((Collection) strings)); } StringBuilder buf = new StringBuilder(); Iterator i = strings.iterator(); if (i.hasNext()) { buf.append(i.next()); while (i.hasNext()) buf.append(glue).append(i.next()); } return buf.toString(); } public static String join(String glue, String... strings) { return join(glue, Arrays.asList(strings)); } public static String join(String glue, Object... strings) { return join(glue, Arrays.asList(strings)); } static String join(Iterable strings) { return join("", strings); } static String join(Iterable strings, String glue) { return join(glue, strings); } public static String join(String[] strings) { return join("", strings); } static String join(String glue, Pair p) { return p == null ? "" : str(p.a) + glue + str(p.b); } static List map_nonNulls(Iterable l, Object f) { return mapNonNulls(l, f); } static List map_nonNulls(Object f, Iterable l) { return mapNonNulls(f, l); } static List map_nonNulls(Object f, Object[] l) { return mapNonNulls(f, l); } static List map_nonNulls(Iterable l, F1 f) { return mapNonNulls(l, f); } static List map_nonNulls(F1 f, Iterable l) { return mapNonNulls(f, l); } static List map_nonNulls(A[] l, IF1 f) { return mapNonNulls(l, f); } static List map_nonNulls(Iterable l, IF1 f) { return mapNonNulls(l, f); } static List map_nonNulls(IF1 f, Iterable l) { return mapNonNulls(f, l); } static void assertSame(Object a, Object b) { assertSame("", a, b); } static void assertSame(String msg, Object a, Object b) { if (a != b) throw fail(joinNemptiesWithColon(msg, a + " != " + b + " (" + identityHash(a) + "/" + identityHash(b) + ")")); } static int min(int a, int b) { return Math.min(a, b); } static long min(long a, long b) { return Math.min(a, b); } static float min(float a, float b) { return Math.min(a, b); } static float min(float a, float b, float c) { return min(min(a, b), c); } static double min(double a, double b) { return Math.min(a, b); } static double min(double[] c) { double x = Double.MAX_VALUE; for (double d : c) x = Math.min(x, d); return x; } static float min(float[] c) { float x = Float.MAX_VALUE; for (float d : c) x = Math.min(x, d); return x; } static byte min(byte[] c) { byte x = 127; for (byte d : c) if (d < x) x = d; return x; } static short min(short[] c) { short x = 0x7FFF; for (short d : c) if (d < x) x = d; return x; } static int min(int[] c) { int x = Integer.MAX_VALUE; for (int d : c) if (d < x) x = d; return x; } static int max(int a, int b) { return Math.max(a, b); } static int max(int a, int b, int c) { return max(max(a, b), c); } static long max(int a, long b) { return Math.max((long) a, b); } static long max(long a, long b) { return Math.max(a, b); } static double max(int a, double b) { return Math.max((double) a, b); } static float max(float a, float b) { return Math.max(a, b); } static double max(double a, double b) { return Math.max(a, b); } static int max(Collection c) { int x = Integer.MIN_VALUE; for (int i : c) x = max(x, i); return x; } static double max(double[] c) { if (c.length == 0) return Double.MIN_VALUE; double x = c[0]; for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]); return x; } static float max(float[] c) { if (c.length == 0) return Float.MAX_VALUE; float x = c[0]; for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]); return x; } static byte max(byte[] c) { byte x = -128; for (byte d : c) if (d > x) x = d; return x; } static short max(short[] c) { short x = -0x8000; for (short d : c) if (d > x) x = d; return x; } static int max(int[] c) { int x = Integer.MIN_VALUE; for (int d : c) if (d > x) x = d; return x; } static > A max(A a, A b) { return cmp(a, b) >= 0 ? a : b; } // get purpose 1: access a list/array/map (safer version of x.get(y)) static A get(List l, int idx) { return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null; } // seems to conflict with other signatures /*static B get(Map map, A key) { ret map != null ? map.get(key) : null; }*/ static A get(A[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : null; } // default to false static boolean get(boolean[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : false; } // get purpose 2: access a field by reflection or a map static Object get(Object o, String field) { try { if (o == null) return null; if (o instanceof Class) return get((Class) o, field); if (o instanceof Map) return ((Map) o).get(field); Field f = getOpt_findField(o.getClass(), field); if (f != null) { makeAccessible(f); return f.get(o); } if (o instanceof DynamicObject) return getOptDynOnly(((DynamicObject) o), field); } catch (Exception e) { throw asRuntimeException(e); } throw new RuntimeException("Field '" + field + "' not found in " + o.getClass().getName()); } static Object get_raw(String field, Object o) { return get_raw(o, field); } static Object get_raw(Object o, String field) { try { if (o == null) return null; Field f = get_findField(o.getClass(), field); makeAccessible(f); return f.get(o); } catch (Exception __e) { throw rethrow(__e); } } static Object get(Class c, String field) { try { Field f = get_findStaticField(c, field); makeAccessible(f); return f.get(null); } catch (Exception e) { throw new RuntimeException(e); } } static Field get_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); } static Field get_findField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field)) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); } static Object get(String field, Object o) { return get(o, field); } static boolean get(BitSet bs, int idx) { return bs != null && bs.get(idx); } static List englishWeekdays_list = ll("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); static List englishWeekdays() { return englishWeekdays_list; } static int dayOfWeek_nr() { return dayOfWeek_nr(java.util.Calendar.getInstance()); } static int dayOfWeek_nr(java.util.Calendar calendar) { return calendar.get(java.util.Calendar.DAY_OF_WEEK); } static int dayOfWeek_nr(long time) { return dayOfWeek_nr(calendarFromTime(time)); } static int dayOfWeek_nr(long time, TimeZone tz) { return dayOfWeek_nr(calendarFromTime(time, tz)); } static String asString(Object o) { return o == null ? null : o.toString(); } static IterableIterator filterI(Iterator it, F1 f) { return filterIterator(it, f); } static IterableIterator filterI(Iterator it, IF1 f) { return filterIterator(it, f); } static IterableIterator filterI(F1 f, Iterator it) { return filterIterator(f, it); } static IterableIterator filterI(IF1 f, Iterator it) { return filterIterator(f, it); } static IterableIterator filterI(IF1 f, Iterable it) { return filterIterator(f, iterator(it)); } static Iterator iterator(Iterable c) { return c == null ? emptyIterator() : c.iterator(); } static String str(Object o) { return o == null ? "null" : o.toString(); } static String str(char[] c) { return new String(c); } static boolean isBetween(long x, long min, long max) { return x >= min && x <= max; } static boolean isBetween(double x, double min, double max) { return x >= min && x <= max; } static IterableIterator emptyItIt() { return emptyIterableIterator(); } static int l(Object[] a) { return a == null ? 0 : a.length; } static int l(boolean[] a) { return a == null ? 0 : a.length; } static int l(byte[] a) { return a == null ? 0 : a.length; } static int l(short[] a) { return a == null ? 0 : a.length; } static int l(long[] a) { return a == null ? 0 : a.length; } static int l(int[] a) { return a == null ? 0 : a.length; } static int l(float[] a) { return a == null ? 0 : a.length; } static int l(double[] a) { return a == null ? 0 : a.length; } static int l(char[] a) { return a == null ? 0 : a.length; } static int l(Collection c) { return c == null ? 0 : c.size(); } static int l(Iterator i) { return iteratorCount_int_close(i); } // consumes the iterator && closes it if possible static int l(Map m) { return m == null ? 0 : m.size(); } static int l(CharSequence s) { return s == null ? 0 : s.length(); } static long l(File f) { return f == null ? 0 : f.length(); } static int l(Object o) { return o == null ? 0 : o instanceof String ? l((String) o) : o instanceof Map ? l((Map) o) : o instanceof Collection ? l((Collection) o) : o instanceof Object[] ? l((Object[]) o) : o instanceof boolean[] ? l((boolean[]) o) : o instanceof byte[] ? l((byte[]) o) : o instanceof char[] ? l((char[]) o) : o instanceof short[] ? l((short[]) o) : o instanceof int[] ? l((int[]) o) : o instanceof float[] ? l((float[]) o) : o instanceof double[] ? l((double[]) o) : o instanceof long[] ? l((long[]) o) : (Integer) call(o, "size"); } static boolean emptyString(String s) { return s == null || s.length() == 0; } static TreeSet caseInsensitiveSet() { return caseInsensitiveSet_treeSet(); } static TreeSet caseInsensitiveSet(Collection c) { return caseInsensitiveSet_treeSet(c); } static TreeSet treeSet() { return new TreeSet(); } static int indexOfIC(List a, String b) { return indexOfIgnoreCase(a, b); } static int indexOfIC(List a, String b, int i) { return indexOfIgnoreCase(a, b, i); } static int indexOfIC(String[] a, String b) { return indexOfIC(a, b, 0); } static int indexOfIC(String[] a, String b, int i) { return indexOfIgnoreCase(a, b, i); } static int indexOfIC(String a, String b) { return indexOfIgnoreCase(a, b); } static int indexOfIC(String a, String b, int i) { return indexOfIgnoreCase(a, b, i); } static Map listIndexCI(List l) { Map map = ciMap(); for (int i = 0; i < l(l); i++) map.put(l.get(i), i); return map; } static List englishMonthNames() { return englishMonthName_data; } static A or(A a, A b) { return a != null ? a : b; } static int countPrecedingTokens(ListAndIndex l) { return l == null ? 0 : l.idx/2; } static IterableIterator countIterator_inclusive(final int a, final int b) { return countIterator_exclusive(a, b+1); } static IterableIterator countIterator_inclusive(int a, int b, IF1 f) { return countIterator_inclusive(a, b, 1, f); } static IterableIterator countIterator_inclusive(int a, int b, int step, IF1 f) { return countIterator_inclusive_step(a, b, 1, f); } static IterableIterator countIterator_inclusive(double a, double b, double step, IF1 f) { return countIterator_inclusive_step(a, b, step, f); } static ParsedWithTokens pwt_raw(List tok, int iStart, int iEnd) { return new ParsedWithTokens(joinSubList(tok, iStart, iEnd), tok, iStart, iEnd); } static int countRemainingTokens(ListAndIndex l) { return l == null ? 0 : (l.size()-l.idx)/2; } static List englishMonthName_data = ll("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"); // nr = 1 to 12 static String englishMonthName(int nr) { return get(englishMonthName_data, nr-1); } static List immutableEmptyList() { return Collections.emptyList(); } static int[] emptyIntArray_a = new int[0]; static int[] emptyIntArray() { return emptyIntArray_a; } static char[] emptyCharArray = new char[0]; static char[] emptyCharArray() { return emptyCharArray; } static double[] emptyDoubleArray = new double[0]; static double[] emptyDoubleArray() { return emptyDoubleArray; } static short[] emptyShortArray = new short[0]; static short[] emptyShortArray() { return emptyShortArray; } static Map immutableEmptyMap() { return Collections.emptyMap(); } static Object[] emptyObjectArray_a = new Object[0]; static Object[] emptyObjectArray() { return emptyObjectArray_a; } static Symbol emptySymbol_value; static Symbol emptySymbol() { if (emptySymbol_value == null) emptySymbol_value = symbol(""); return emptySymbol_value; } static void listSet(List l, int i, A a, A emptyElement) { if (i < 0) return; while (i >= l(l)) l.add(emptyElement); l.set(i, a); } static void listSet(List l, int i, A a) { listSet(l, i, a, null); } static List uniquifyList(Collection l) { if (l == null) return null; if (l(l) < 2) return asList(l); HashSet set = new HashSet(); List out = new ArrayList(); for (A a : l) if (set.add(a)) out.add(a); return out; } static List withoutNulls(Iterable l) { if (l instanceof List) if (!containsNulls((List) l)) return ((List) l); List l2 = new ArrayList(); for (A a : l) if (a != null) l2.add(a); return l2; } static Map withoutNulls(Map map) { Map map2 = similarEmptyMap(map); for (A a : keys(map)) if (a != null) { B b = map.get(a); if (b != null) map2.put(a, b); } return map2; } static List withoutNulls(A[] l) { List l2 = new ArrayList(); if (l != null) for (A a : l) if (a != null) l2.add(a); return l2; } static boolean isTrue(Object o) { if (o instanceof Boolean) return ((Boolean) o).booleanValue(); if (o == null) return false; if (o instanceof ThreadLocal) // TODO: remove this return isTrue(((ThreadLocal) o).get()); throw fail(getClassName(o)); } static boolean isTrue(Boolean b) { return b != null && b.booleanValue(); } static Map> callF_cache = newDangerousWeakHashMap(); static A callF(F0 f) { return f == null ? null : f.get(); } static B callF(F1 f, A a) { return f == null ? null : f.get(a); } static A callF(IF0 f) { return f == null ? null : f.get(); } static B callF(IF1 f, A a) { return f == null ? null : f.get(a); } static B callF(A a, IF1 f) { return f == null ? null : f.get(a); } static C callF(IF2 f, A a, B b) { return f == null ? null : f.get(a, b); } static void callF(VF1 f, A a) { if (f != null) f.get(a); } static void callF(A a, IVF1 f) { if (f != null) f.get(a); } static void callF(IVF1 f, A a) { if (f != null) f.get(a); } static Object callF(Runnable r) { { if (r != null) r.run(); } return null; } static Object callF(Object f, Object... args) { return safeCallF(f, args); } static Object safeCallF(Object f, Object... args) { if (f instanceof Runnable) { ((Runnable) f).run(); return null; } if (f == null) return null; Class c = f.getClass(); ArrayList methods; synchronized(callF_cache) { methods = callF_cache.get(c); if (methods == null) methods = callF_makeCache(c); } int n = l(methods); if (n == 0) { if (f instanceof String) throw fail("Legacy call: " + f); throw fail("No get method in " + getClassName(c)); } if (n == 1) return invokeMethod(methods.get(0), f, args); for (int i = 0; i < n; i++) { Method m = methods.get(i); if (call_checkArgs(m, args, false)) return invokeMethod(m, f, args); } throw fail("No matching get method in " + getClassName(c)); } // used internally static ArrayList callF_makeCache(Class c) { ArrayList l = new ArrayList(); Class _c = c; do { for (Method m : _c.getDeclaredMethods()) if (m.getName().equals("get")) { makeAccessible(m); l.add(m); } if (!l.isEmpty()) break; _c = _c.getSuperclass(); } while (_c != null); callF_cache.put(c, l); return l; } static RuntimeException fail() { throw new RuntimeException("fail"); } static RuntimeException fail(Throwable e) { throw asRuntimeException(e); } static RuntimeException fail(Object msg) { throw new RuntimeException(String.valueOf(msg)); } static RuntimeException fail(Object... objects) { throw new Fail(objects); } static RuntimeException fail(String msg) { throw new RuntimeException(msg == null ? "" : msg); } static RuntimeException fail(String msg, Throwable innerException) { throw new RuntimeException(msg, innerException); } static String getType(Object o) { return getClassName(o); } static long getFileSize(String path) { return path == null ? 0 : new File(path).length(); } static long getFileSize(File f) { return f == null ? 0 : f.length(); } static Set> _entrySet(Map map) { return map == null ? Collections.EMPTY_SET : map.entrySet(); } static List concatLists(Iterable... lists) { List l = new ArrayList(); if (lists != null) for (Iterable list : lists) addAll(l, list); return l; } static List concatLists(Collection> lists) { List l = new ArrayList(); if (lists != null) for (Iterable list : lists) addAll(l, list); return l; } static List map(Iterable l, Object f) { return map(f, l); } static List map(Object f, Iterable l) { List x = emptyList(l); if (l != null) for (Object o : l) { ping(); x.add(callF(f, o)); } return x; } static List map(Iterable l, F1 f) { return map(f, l); } static List map(F1 f, Iterable l) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(callF(f, o)); } return x; } static List map(IF1 f, Iterable l) { return map(l, f); } static List map(Iterable l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(f.get(o)); } return x; } static List map(IF1 f, A[] l) { return map(l, f); } static List map(A[] l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(f.get(o)); } return x; } static List map(Object f, Object[] l) { return map(f, asList(l)); } static List map(Object[] l, Object f) { return map(f, l); } static List map(Object f, Map map) { return map(map, f); } // map: func(key, value) -> list element static List map(Map map, Object f) { List x = new ArrayList(); if (map != null) for (Object _e : map.entrySet()) { ping(); Map.Entry e = (Map.Entry) _e; x.add(callF(f, e.getKey(), e.getValue())); } return x; } static List map(Map map, IF2 f) { return map(map, (Object) f); } // new magic alias for mapLL - does it conflict? static List map(IF1 f, A data1, A... moreData) { List x = emptyList(l(moreData)+1); x.add(f.get(data1)); if (moreData != null) for (A o : moreData) { ping(); x.add(f.get(o)); } return x; } static IterableIterator codeTokenIndices(List tok) { return countIterator_exclusive_step(1, l(tok) & ~1, 2); } static List mapNonNulls(Iterable l, Object f) { return mapNonNulls(f, l); } static List mapNonNulls(Object f, Iterable l) { List x = new ArrayList(); if (l != null) for (Object o : l) addIfNotNull(x, callF(f, o)); return x; } static List mapNonNulls(Object f, Object[] l) { List x = new ArrayList(); if (l != null) for (Object o : l) addIfNotNull(x, callF(f, o)); return x; } static List mapNonNulls(Iterable l, F1 f) { return mapNonNulls(f, l); } static List mapNonNulls(F1 f, Iterable l) { List x = new ArrayList(); if (l != null) for (Object o : l) addIfNotNull(x, callF(f, o)); return x; } static List mapNonNulls(A[] l, IF1 f) { return mapNonNulls(f, l); } static List mapNonNulls(Iterable l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : l) addIfNotNull(x, f.get(o)); return x; } static List mapNonNulls(IF1 f, Iterable l) { return mapNonNulls(l, f); } static String joinNemptiesWithColon(String... strings) { return joinNempties(": ", strings); } static String joinNemptiesWithColon(Collection strings) { return joinNempties(": ", strings); } static int identityHash(Object o) { return identityHashCode(o); } static int cmp(Number a, Number b) { return a == null ? b == null ? 0 : -1 : cmp(a.doubleValue(), b.doubleValue()); } static int cmp(double a, double b) { return a < b ? -1 : a == b ? 0 : 1; } static int cmp(int a, int b) { return a < b ? -1 : a == b ? 0 : 1; } static int cmp(long a, long b) { return a < b ? -1 : a == b ? 0 : 1; } static int cmp(Object a, Object b) { if (a == null) return b == null ? 0 : -1; if (b == null) return 1; return ((Comparable) a).compareTo(b); } static Field getOpt_findField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field)) return f; _c = _c.getSuperclass(); } while (_c != null); return null; } static Field makeAccessible(Field f) { try { f.setAccessible(true); } catch (Throwable e) { // Note: The error reporting only works with Java VM option --illegal-access=deny vmBus_send("makeAccessible_error", e, f); } return f; } static Method makeAccessible(Method m) { try { m.setAccessible(true); } catch (Throwable e) { vmBus_send("makeAccessible_error", e, m); } return m; } static Constructor makeAccessible(Constructor c) { try { c.setAccessible(true); } catch (Throwable e) { vmBus_send("makeAccessible_error", e, c); } return c; } static Object getOptDynOnly(DynamicObject o, String field) { if (o == null || o.fieldValues == null) return null; return o.fieldValues.get(field); } static RuntimeException asRuntimeException(Throwable t) { if (t instanceof Error) _handleError((Error) t); return t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static RuntimeException rethrow(Throwable t) { if (t instanceof Error) _handleError((Error) t); throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static RuntimeException rethrow(String msg, Throwable t) { throw new RuntimeException(msg, t); } static List ll(A... a) { ArrayList l = new ArrayList(a.length); if (a != null) for (A x : a) l.add(x); return l; } static java.util.Calendar calendarFromTime(long time, TimeZone tz) { java.util.Calendar c = java.util.Calendar.getInstance(tz); c.setTimeInMillis(time); return c; } static java.util.Calendar calendarFromTime(long time) { java.util.Calendar c = java.util.Calendar.getInstance(); c.setTimeInMillis(time); return c; } static IterableIterator filterIterator(final Iterator it, final F1 f) { if (it == null) return null; return iff(new F0() { public Object get() { try { while (it.hasNext()) { A a = it.next(); if (callF(f, a)) return a; } return endMarker(); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "while (it.hasNext()) {\r\n A a = it.next();\r\n if (callF(f, a))\r\n ..."; }}); } static IterableIterator filterIterator(final Iterator it, final IF1 f) { if (it == null) return null; return iff(new F0() { public Object get() { try { while (it.hasNext()) { A a = it.next(); if (callF(f, a)) return a; } return endMarker(); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "while (it.hasNext()) {\r\n A a = it.next();\r\n if (callF(f, a))\r\n ..."; }}); } static IterableIterator filterIterator(final F1 f, final Iterator it) { return filterIterator(it, f); } static IterableIterator filterIterator(Collection l, IF1 f) { if (l == null) return null; Iterator it = iterator(l); return iff(new F0() { public Object get() { try { while (it.hasNext()) { A a = it.next(); if (f.get(a)) return a; } return endMarker(); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "while (it.hasNext()) {\r\n A a = it.next();\r\n if (f.get(a))\r\n ..."; }}); } static IterableIterator filterIterator(IF1 f, Iterator it) { return filterIterator(it, f); } static Iterator emptyIterator() { return Collections.emptyIterator(); } static IterableIterator emptyIterableIterator_instance = new IterableIterator() { public Object next() { throw fail(); } public boolean hasNext() { return false; } }; static IterableIterator emptyIterableIterator() { return emptyIterableIterator_instance; } static int iteratorCount_int_close(Iterator i) { try { int n = 0; if (i != null) while (i.hasNext()) { i.next(); ++n; } if (i instanceof AutoCloseable) ((AutoCloseable) i).close(); return n; } catch (Exception __e) { throw rethrow(__e); } } static Object call(Object o) { return callF(o); } // varargs assignment fixer for a single string array argument static Object call(Object o, String method, String[] arg) { return call(o, method, new Object[] {arg}); } static Object call(Object o, String method, Object... args) { //ret call_cached(o, method, args); return call_withVarargs(o, method, args); } static TreeSet caseInsensitiveSet_treeSet() { return new TreeSet(caseInsensitiveComparator()); } static TreeSet caseInsensitiveSet_treeSet(Collection c) { return toCaseInsensitiveSet_treeSet(c); } // works on lists and strings and null static int indexOfIgnoreCase(List a, String b) { return indexOfIgnoreCase(a, b, 0); } static int indexOfIgnoreCase(List a, String b, int i) { int n = a == null ? 0 : a.size(); for (; i < n; i++) if (eqic(a.get(i), b)) return i; return -1; } static int indexOfIgnoreCase(String[] a, String b) { return indexOfIgnoreCase(a, b, 0); } static int indexOfIgnoreCase(String[] a, String b, int i) { int n = a == null ? 0 : a.length; for (; i < n; i++) if (eqic(a[i], b)) return i; return -1; } static int indexOfIgnoreCase(String a, String b) { return indexOfIgnoreCase_manual(a, b); /*Matcher m = Pattern.compile(b, Pattern.CASE_INSENSITIVE + Pattern.LITERAL).matcher(a); if (m.find()) return m.start(); else ret -1;*/ } static int indexOfIgnoreCase(String a, String b, int i) { return indexOfIgnoreCase_manual(a, b, i); } static TreeMap ciMap() { return caseInsensitiveMap(); } static IterableIterator countIterator_exclusive(int b) { return countIterator_exclusive(0, b); } static IterableIterator countIterator_exclusive(int a, int b) { return new IterableIterator() { int i = a; public boolean hasNext() { return i < b; } public Integer next() { return i++; } }; } static IterableIterator countIterator_exclusive(int b, IF1 f) { return countIterator_exclusive(0, b, f); } static IterableIterator countIterator_exclusive(int a, int b, IF1 f) { return mapI_if1(f, countIterator_exclusive(a, b)); } static IterableIterator countIterator_inclusive_step(int a, final int b, int step) { assertTrue("step > 0", step > 0); return new IterableIterator() { int i = a; public boolean hasNext() { return i <= b; } public Integer next() { var j = i; i += step; return j; } }; } static IterableIterator countIterator_inclusive_step(double a, double b, double step) { assertTrue("step > 0", step > 0); return new IterableIterator() { double i = a; public boolean hasNext() { return i <= b; } public Double next() { var j = i; i += step; return j; } }; } static IterableIterator countIterator_inclusive_step(double a, double b, double step, IF1 f) { return mapI_if1(f, countIterator_inclusive_step(a, b, step)); } static IterableIterator countIterator_inclusive_step(int a, int b, int step, IF1 f) { return mapI_if1(f, countIterator_inclusive_step(a, b, step)); } static String joinSubList(List l, int i, int j) { return join(subList(l, i, j)); } static String joinSubList(List l, int i) { return join(subList(l, i)); } static WeakHasherMap symbol_map = new WeakHasherMap(new Hasher() { public int hashCode(Symbol symbol) { return symbol.text.hashCode(); } public boolean equals(Symbol a, Symbol b) { if (a == null) return b == null; return b != null && eq(a.text, b.text); } }); static Symbol symbol(String s) { if (s == null) return null; synchronized(symbol_map) { // TODO: avoid object creation by passing the string to findKey Symbol symbol = new Symbol(s, true); Symbol existingSymbol = symbol_map.findKey(symbol); if (existingSymbol == null) symbol_map.put(existingSymbol = symbol, true); return existingSymbol; } } static Symbol symbol(CharSequence s) { if (s == null) return null; if (s instanceof Symbol) return (Symbol) s; if (s instanceof String) return symbol((String) s); return symbol(str(s)); } static Symbol symbol(Object o) { return symbol((CharSequence) o); } // unclear semantics as to whether return null on null static ArrayList asList(A[] a) { return a == null ? new ArrayList() : new ArrayList(Arrays.asList(a)); } static ArrayList asList(int[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (int i : a) l.add(i); return l; } static ArrayList asList(long[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (long i : a) l.add(i); return l; } static ArrayList asList(float[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (float i : a) l.add(i); return l; } static ArrayList asList(double[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (double i : a) l.add(i); return l; } static ArrayList asList(short[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (short i : a) l.add(i); return l; } static ArrayList asList(Iterator it) { ArrayList l = new ArrayList(); if (it != null) while (it.hasNext()) l.add(it.next()); return l; } // disambiguation static ArrayList asList(IterableIterator s) { return asList((Iterator) s); } static ArrayList asList(Iterable s) { if (s instanceof ArrayList) return (ArrayList) s; ArrayList l = new ArrayList(); if (s != null) for (A a : s) l.add(a); return l; } static ArrayList asList(Enumeration e) { ArrayList l = new ArrayList(); if (e != null) while (e.hasMoreElements()) l.add(e.nextElement()); return l; } static List asList(Pair p) { return p == null ? null : ll(p.a, p.b); } static boolean containsNulls(Collection c) { return contains(c, null); } static Map similarEmptyMap(Map m) { if (m instanceof TreeMap) return new TreeMap(((TreeMap) m).comparator()); if (m instanceof LinkedHashMap) return new LinkedHashMap(); // default to a hash map return new HashMap(); } static Map similarEmptyMap(Iterable m) { if (m instanceof TreeSet) return new TreeMap(((TreeSet) m).comparator()); if (m instanceof LinkedHashSet) return new LinkedHashMap(); return new HashMap(); } static Set keys(Map map) { return map == null ? new HashSet() : map.keySet(); } // convenience shortcut for keys_gen static Set keys(Object map) { return keys((Map) map); } static Set keys(MultiMap mm) { return mm.keySet(); } static String getClassName(Object o) { return o == null ? "null" : o instanceof Class ? ((Class) o).getName() : o.getClass().getName(); } static Map newDangerousWeakHashMap() { return _registerDangerousWeakMap(synchroMap(new WeakHashMap())); } // initFunction: voidfunc(Map) - is called initially, and after clearing the map static Map newDangerousWeakHashMap(Object initFunction) { return _registerDangerousWeakMap(synchroMap(new WeakHashMap()), initFunction); } static Object invokeMethod(Method m, Object o, Object... args) { try { try { return m.invoke(o, args); } catch (InvocationTargetException e) { throw rethrow(getExceptionCause(e)); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(e.getMessage() + " - was calling: " + m + ", args: " + joinWithSpace(classNames(args))); } } catch (Exception __e) { throw rethrow(__e); } } static boolean call_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != args.length) { if (debug) print("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) { Object arg = args[i]; if (!(arg == null ? !types[i].isPrimitive() : isInstanceX(types[i], arg))) { if (debug) print("Bad parameter " + i + ": " + arg + " vs " + types[i]); return false; } } return true; } static void addAll(Collection c, Iterable b) { if (c != null && b != null) for (A a : b) c.add(a); } static boolean addAll(Collection c, Collection b) { return c != null && b != null && c.addAll(b); } static boolean addAll(Collection c, B... b) { return c != null && b != null && c.addAll(Arrays.asList(b)); } static Map addAll(Map a, Map b) { if (a != null && b != null) a.putAll(b); return a; } static ArrayList emptyList() { return new ArrayList(); //ret Collections.emptyList(); } static ArrayList emptyList(int capacity) { return new ArrayList(max(0, capacity)); } // Try to match capacity static ArrayList emptyList(Iterable l) { return l instanceof Collection ? emptyList(((Collection) l).size()) : emptyList(); } static ArrayList emptyList(Object[] l) { return emptyList(l(l)); } // get correct type at once static ArrayList emptyList(Class c) { return new ArrayList(); } //sbool ping_actions_shareable = true; static volatile boolean ping_pauseAll = false; static int ping_sleep = 100; // poll pauseAll flag every 100 static volatile boolean ping_anyActions = false; static Map ping_actions = newWeakHashMap(); static ThreadLocal ping_isCleanUpThread = new ThreadLocal(); // always returns true static boolean ping() { //ifdef useNewPing newPing(); //endifdef if (ping_pauseAll || ping_anyActions) ping_impl(true /* XXX */); //ifndef LeanMode ping_impl(); endifndef return true; } // returns true when it slept static boolean ping_impl(boolean okInCleanUp) { try { if (ping_pauseAll && !isAWTThread()) { do Thread.sleep(ping_sleep); while (ping_pauseAll); return true; } if (ping_anyActions) { // don't allow sharing ping_actions if (!okInCleanUp && !isTrue(ping_isCleanUpThread.get())) failIfUnlicensed(); Object action = null; synchronized(ping_actions) { if (!ping_actions.isEmpty()) { action = ping_actions.get(currentThread()); if (action instanceof Runnable) ping_actions.remove(currentThread()); if (ping_actions.isEmpty()) ping_anyActions = false; } } if (action instanceof Runnable) ((Runnable) action).run(); else if (eq(action, "cancelled")) throw fail("Thread cancelled."); } return false; } catch (Exception __e) { throw rethrow(__e); } } static IterableIterator countIterator_exclusive_step(final int a, final int b, final int step) { assertTrue("step > 0", step > 0); return new IterableIterator() { int i = a; public boolean hasNext() { return i < b; } public Integer next() { var j = i; i += step; return j; } }; } static IterableIterator countIterator_exclusive_step(double a, double b, double step) { assertTrue("step > 0", step > 0); return new IterableIterator() { double i = a; public boolean hasNext() { return i < b; } public Double next() { var j = i; i += step; return j; } }; } static IterableIterator countIterator_exclusive_step(double a, double b, double step, IF1 f) { return mapI_if1(f, countIterator_exclusive_step(a, b, step)); } static boolean addIfNotNull(Collection l, A a) { return a != null && l != null & l.add(a); } static String joinNempties(String sep, Object... strings) { return joinStrings(sep, strings); } static String joinNempties(String sep, Iterable strings) { return joinStrings(sep, strings); } static int identityHashCode(Object o) { return System.identityHashCode(o); } static void vmBus_send(String msg, Object... args) { Object arg = vmBus_wrapArgs(args); pcallFAll_minimalExceptionHandling(vm_busListeners_live(), msg, arg); pcallFAll_minimalExceptionHandling(vm_busListenersByMessage_live().get(msg), msg, arg); } static void vmBus_send(String msg) { vmBus_send(msg, (Object) null); } static void _handleError(Error e) { call(javax(), "_handleError", e); } // f: func -> A | endMarker static IterableIterator iff(Object f) { return iteratorFromFunction_withEndMarker(f); } // can't use type parameter because end marker static IterableIterator iff(F0 f) { return iteratorFromFunction_withEndMarker(f); } static IterableIterator iff(IF0 f) { return iteratorFromFunction_withEndMarker(f); } static Object endMarker() { return iteratorFromFunction_endMarker; } static Object call_withVarargs(Object o, String method, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); Method me = cache.findStaticMethod(method, args); if (me != null) return invokeMethod(me, null, args); // try varargs List methods = cache.cache.get(method); if (methods != null) methodSearch: for (Method m : methods) { { if (!(m.isVarArgs())) continue; } { if (!(isStaticMethod(m))) continue; } Object[] newArgs = massageArgsForVarArgsCall(m, args); if (newArgs != null) return invokeMethod(m, null, newArgs); } throw fail("Method " + c.getName() + "." + method + "(" + joinWithComma(classNames(args)) + ") not found"); } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(method, args); if (me != null) return invokeMethod(me, o, args); // try varargs List methods = cache.cache.get(method); if (methods != null) methodSearch: for (Method m : methods) { { if (!(m.isVarArgs())) continue; } Object[] newArgs = massageArgsForVarArgsCall(m, args); if (newArgs != null) return invokeMethod(m, o, newArgs); } throw fail("Method " + c.getName() + "." + method + "(" + joinWithComma(classNames(args)) + ") not found"); } } catch (Exception __e) { throw rethrow(__e); } } static Comparator caseInsensitiveComparator() { return betterCIComparator(); } static TreeSet toCaseInsensitiveSet_treeSet(Iterable c) { if (isCISet(c)) return (TreeSet) c; TreeSet set = caseInsensitiveSet_treeSet(); addAll(set, c); return set; } static TreeSet toCaseInsensitiveSet_treeSet(String... x) { TreeSet set = caseInsensitiveSet_treeSet(); addAll(set, x); return set; } static int indexOfIgnoreCase_manual(String a, String b) { return indexOfIgnoreCase_manual(a, b, 0); } static int indexOfIgnoreCase_manual(String a, String b, int i) { int la = strL(a), lb = strL(b); if (la < lb) return -1; int n = la-lb; loop: for (; i <= n; i++) { for (int j = 0; j < lb; j++) { char c1 = a.charAt(i+j), c2 = b.charAt(j); if (!eqic(c1, c2)) continue loop; } return i; } return -1; } static TreeMap caseInsensitiveMap() { return new TreeMap(caseInsensitiveComparator()); } static class mapI_if1_It extends IterableIterator { IF1 f; Iterator i; mapI_if1_It() {} mapI_if1_It(IF1 f, Iterator i) { this.i = i; this.f = f;} public boolean hasNext() { return i.hasNext(); } public B next() { return f.get(i.next()); } public String toString() { return formatFunctionCall("mapI_if1", f, i); } } static IterableIterator mapI_if1(IF1 f, Iterable i) { return new mapI_if1_It(f, i.iterator()); } static IterableIterator mapI_if1(Iterable i, IF1 f) { return mapI_if1(f, i); } static void assertTrue(Object o) { if (!(eq(o, true) /*|| isTrue(pcallF(o))*/)) throw fail(str(o)); } static boolean assertTrue(String msg, boolean b) { if (!b) throw fail(msg); return b; } static boolean assertTrue(boolean b) { if (!b) throw fail("oops"); return b; } static List subList(List l, int startIndex) { return subList(l, startIndex, l(l)); } static List subList(int startIndex, List l) { return subList(l, startIndex); } static List subList(int startIndex, int endIndex, List l) { return subList(l, startIndex, endIndex); } static List subList(List l, int startIndex, int endIndex) { if (l == null) return null; int n = l(l); startIndex = Math.max(0, startIndex); endIndex = Math.min(n, endIndex); if (startIndex > endIndex) return ll(); if (startIndex == 0 && endIndex == n) return l; return l.subList(startIndex, endIndex); } // requires ugly casting when used (O -> A) static Object iteratorFromFunction_endMarker = new Object(); // f: func -> A | endMarker static IterableIterator iteratorFromFunction_withEndMarker(final Object f) { class IFF extends IterableIterator { A a; boolean have, done; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; have = false; return _a; } void getNext() { if (done || have) return; Object o = callF(f); if (o == iteratorFromFunction_endMarker) { done = true; return; } a = (A) o; have = true; } }; return new IFF(); } // optimized version for F0 argument; TODO: do same for IF0 static IterableIterator iteratorFromFunction_withEndMarker(final F0 f) { return iteratorFromFunction_withEndMarker_f0(f); } static List _registerDangerousWeakMap_preList; static A _registerDangerousWeakMap(A map) { return _registerDangerousWeakMap(map, null); } static A _registerDangerousWeakMap(A map, Object init) { callF(init, map); if (init instanceof String) { final String f = (String) init; init = new VF1() { public void get(Map map) { try { callMC(f, map) ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "callMC(f, map)"; }}; } if (javax() == null) { // We're in class init if (_registerDangerousWeakMap_preList == null) _registerDangerousWeakMap_preList = synchroList(); _registerDangerousWeakMap_preList.add(pair(map, init)); return map; } call(javax(), "_registerDangerousWeakMap", map, init); return map; } static void _onLoad_registerDangerousWeakMap() { assertNotNull(javax()); if (_registerDangerousWeakMap_preList == null) return; for (Pair p : _registerDangerousWeakMap_preList) _registerDangerousWeakMap(p.a, p.b); _registerDangerousWeakMap_preList = null; } static Map synchroMap() { return synchroHashMap(); } static Map synchroMap(Map map) { return Collections.synchronizedMap(map); } static Throwable getExceptionCause(Throwable e) { Throwable c = e.getCause(); return c != null ? c : e; } static String joinWithSpace(Iterable c) { return join(" ", c); } static String joinWithSpace(String... c) { return join(" ", c); } static List classNames(Collection l) { return getClassNames(l); } static List classNames(Object[] l) { return getClassNames(Arrays.asList(l)); } static volatile StringBuffer local_log = new StringBuffer(); // not redirected static boolean printAlsoToSystemOut = true; static volatile Appendable print_log = local_log; // might be redirected, e.g. to main bot // in bytes - will cut to half that static volatile int print_log_max = 1024*1024; static volatile int local_log_max = 100*1024; static boolean print_silent = false; // total mute if set static Object print_byThread_lock = new Object(); static volatile ThreadLocal print_byThread; // special handling by thread - prefers F1 static volatile Object print_allThreads; static volatile Object print_preprocess; static void print() { print(""); } static A print(String s, A o) { print(combinePrintParameters(s, o)); return o; } // slightly overblown signature to return original object... static A print(A o) { ping_okInCleanUp(); if (print_silent) return o; String s = o + "\n"; print_noNewLine(s); return o; } static void print_noNewLine(String s) { try { Object f = getThreadLocal(print_byThread_dontCreate()); if (f == null) f = print_allThreads; if (f != null) // We do need the general callF machinery here as print_byThread is sometimes shared between modules if (isFalse( f instanceof F1 ? ((F1) f).get(s) : callF(f, s))) return; } catch (Throwable e) { System.out.println(getStackTrace(e)); } print_raw(s); } static void print_raw(String s) { if (print_preprocess != null) s = (String) callF(print_preprocess, s); s = fixNewLines(s); Appendable loc = local_log; Appendable buf = print_log; int loc_max = print_log_max; if (buf != loc && buf != null) { print_append(buf, s, print_log_max); loc_max = local_log_max; } if (loc != null) print_append(loc, s, loc_max); if (printAlsoToSystemOut) System.out.print(s); vmBus_send("printed", mc(), s); } static void print_autoRotate() { } static boolean isInstanceX(Class type, Object arg) { if (type == boolean.class) return arg instanceof Boolean; if (type == int.class) return arg instanceof Integer; if (type == long.class) return arg instanceof Long; if (type == float.class) return arg instanceof Float; if (type == short.class) return arg instanceof Short; if (type == char.class) return arg instanceof Character; if (type == byte.class) return arg instanceof Byte; if (type == double.class) return arg instanceof Double; return type.isInstance(arg); } static Map newWeakHashMap() { return _registerWeakMap(synchroMap(new WeakHashMap())); } static void newPing() { var tl = newPing_actionTL(); Runnable action = tl == null ? null : tl.get(); { if (action != null) action.run(); } } // TODO: test if android complains about this static boolean isAWTThread() { if (isAndroid()) return false; if (isHeadless()) return false; return isAWTThread_awt(); } static boolean isAWTThread_awt() { return SwingUtilities.isEventDispatchThread(); } static void failIfUnlicensed() { assertTrue("license off", licensed()); } static Thread currentThread() { return Thread.currentThread(); } static String joinStrings(String sep, Object... strings) { return joinStrings(sep, Arrays.asList(strings)); } static String joinStrings(String sep, Iterable strings) { StringBuilder buf = new StringBuilder(); for (Object o : unnull(strings)) { String s = strOrNull(o); if (nempty(s)) { if (nempty(buf)) buf.append(sep); buf.append(s); } } return str(buf); } static Object vmBus_wrapArgs(Object... args) { return empty(args) ? null : l(args) == 1 ? args[0] : args; } static void pcallFAll_minimalExceptionHandling(Collection l, Object... args) { if (l != null) for (Object f : cloneList(l)) { ping(); pcallF_minimalExceptionHandling(f, args); } } static void pcallFAll_minimalExceptionHandling(Iterator it, Object... args) { while (it.hasNext()) { ping(); pcallF_minimalExceptionHandling(it.next(), args); } } static Set vm_busListeners_live_cache; static Set vm_busListeners_live() { if (vm_busListeners_live_cache == null) vm_busListeners_live_cache = vm_busListeners_live_load(); return vm_busListeners_live_cache; } static Set vm_busListeners_live_load() { return vm_generalIdentityHashSet("busListeners"); } static Map vm_busListenersByMessage_live_cache; static Map vm_busListenersByMessage_live() { if (vm_busListenersByMessage_live_cache == null) vm_busListenersByMessage_live_cache = vm_busListenersByMessage_live_load(); return vm_busListenersByMessage_live_cache; } static Map vm_busListenersByMessage_live_load() { return vm_generalHashMap("busListenersByMessage"); } static Class javax() { return getJavaX(); } static final Map callOpt_cache = newDangerousWeakHashMap(); static Object callOpt_cached(Object o, String methodName, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); // TODO: (super-rare) case where method exists static and non-static // with different args Method me = cache.findMethod(methodName, args); if (me == null || (me.getModifiers() & Modifier.STATIC) == 0) return null; return invokeMethod(me, null, args); } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(methodName, args); if (me == null) return null; return invokeMethod(me, o, args); } } catch (Exception __e) { throw rethrow(__e); } } // no longer synchronizes! (see #1102990) static _MethodCache callOpt_getCache(Class c) { _MethodCache cache = callOpt_cache.get(c); if (cache == null) callOpt_cache.put(c, cache = new _MethodCache(c)); return cache; } static boolean isStaticMethod(Method m) { return methodIsStatic(m); } static Object[] massageArgsForVarArgsCall(Method m, Object[] args) { Class[] types = m.getParameterTypes(); int n = types.length-1, nArgs = args.length; if (nArgs < n) return null; for (int i = 0; i < n; i++) if (!argumentCompatibleWithType(args[i], types[i])) return null; Class varArgType = types[n].getComponentType(); for (int i = n; i < nArgs; i++) if (!argumentCompatibleWithType(args[i], varArgType)) return null; Object[] newArgs = new Object[n+1]; arraycopy(args, 0, newArgs, 0, n); Object[] varArgs = arrayOfType(varArgType, nArgs-n); arraycopy(args, n, varArgs, 0, nArgs-n); newArgs[n] = varArgs; return newArgs; } static String joinWithComma(Collection c) { return join(", ", c); } static String joinWithComma(Object... c) { return join(", ", c); } static String joinWithComma(String... c) { return join(", ", c); } static String joinWithComma(Pair p) { return p == null ? "" : joinWithComma(str(p.a), str(p.b)); } static betterCIComparator_C betterCIComparator_instance; static betterCIComparator_C betterCIComparator() { if (betterCIComparator_instance == null) betterCIComparator_instance = new betterCIComparator_C(); return betterCIComparator_instance; } final static class betterCIComparator_C implements Comparator { public int compare(String s1, String s2) { if (s1 == null) return s2 == null ? 0 : -1; if (s2 == null) return 1; int n1 = s1.length(); int n2 = s2.length(); int min = Math.min(n1, n2); for (int i = 0; i < min; i++) { char c1 = s1.charAt(i); char c2 = s2.charAt(i); if (c1 != c2) { c1 = Character.toUpperCase(c1); c2 = Character.toUpperCase(c2); if (c1 != c2) { c1 = Character.toLowerCase(c1); c2 = Character.toLowerCase(c2); if (c1 != c2) { // No overflow because of numeric promotion return c1 - c2; } } } } return n1 - n2; } } static boolean isCISet(Iterable l) { return l instanceof TreeSet && ((TreeSet) l).comparator() == caseInsensitiveComparator(); } static int strL(String s) { return s == null ? 0 : s.length(); } // binary legacy syntax static String formatFunctionCall(String fname, Object... args) { return formatFunctionCall((Object) fname, args); } static String formatFunctionCall(Object fname, Object... args) { return fname + "(" + joinWithComma(allToString(args)) + ")"; } static String formatFunctionCall(String fname, Iterable args) { return formatFunctionCall((Object) fname, args); } static String formatFunctionCall(Object fname, Iterable args) { return formatFunctionCall(fname, toObjectArray(args)); } static AutoCloseable tempInterceptPrintIfNotIntercepted(F1 f) { return print_byThread().get() == null ? tempInterceptPrint(f) : null; } static IterableIterator iteratorFromFunction_withEndMarker_f0(final F0 f) { class IFF2 extends IterableIterator { A a; boolean have, done; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; have = false; return _a; } void getNext() { if (done || have) return; Object o = f.get(); if (o == iteratorFromFunction_endMarker) { done = true; return; } a = (A) o; have = true; } }; return new IFF2(); } static HashMap> callMC_cache = new HashMap(); static String callMC_key; static Method callMC_value; // varargs assignment fixer for a single string array argument static Object callMC(String method, String[] arg) { return callMC(method, new Object[] {arg}); } static Object callMC(String method, Object... args) { try { Method me; if (callMC_cache == null) callMC_cache = new HashMap(); // initializer time workaround synchronized(callMC_cache) { me = method == callMC_key ? callMC_value : null; } if (me != null) try { return invokeMethod(me, null, args); } catch (IllegalArgumentException e) { throw new RuntimeException("Can't call " + me + " with arguments " + classNames(args), e); } List m; synchronized(callMC_cache) { m = callMC_cache.get(method); } if (m == null) { if (callMC_cache.isEmpty()) { callMC_makeCache(); m = callMC_cache.get(method); } if (m == null) throw fail("Method named " + method + " not found in main"); } int n = m.size(); if (n == 1) { me = m.get(0); synchronized(callMC_cache) { callMC_key = method; callMC_value = me; } try { return invokeMethod(me, null, args); } catch (IllegalArgumentException e) { throw new RuntimeException("Can't call " + me + " with arguments " + classNames(args), e); } } for (int i = 0; i < n; i++) { me = m.get(i); if (call_checkArgs(me, args, false)) return invokeMethod(me, null, args); } throw fail("No method called " + method + " with arguments (" + joinWithComma(getClasses(args)) + ") found in main"); } catch (Exception __e) { throw rethrow(__e); } } static void callMC_makeCache() { synchronized(callMC_cache) { callMC_cache.clear(); Class _c = (Class) mc(), c = _c; while (c != null) { for (Method m : c.getDeclaredMethods()) if ((m.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) { makeAccessible(m); multiMapPut(callMC_cache, m.getName(), m); } c = c.getSuperclass(); } } } static List synchroList() { return synchroList(new ArrayList()); } static List synchroList(List l) { return Collections.synchronizedList(l); } static A assertNotNull(A a) { assertTrue(a != null); return a; } static A assertNotNull(String msg, A a) { assertTrue(msg, a != null); return a; } static Map synchroHashMap() { return synchronizedMap(new HashMap()); } static List getClassNames(Collection l) { List out = new ArrayList(); if (l != null) for (Object o : l) out.add(o == null ? null : getClassName(o)); return out; } static String combinePrintParameters(String s, Object o) { return (endsWithLetterOrDigit(s) ? s + ": " : s) + o; } static void ping_okInCleanUp() { if (ping_pauseAll || ping_anyActions) ping_impl(true); } // this syntax should be removed... static Object getThreadLocal(Object o, String name) { ThreadLocal t = (ThreadLocal) (getOpt(o, name)); return t != null ? t.get() : null; } static A getThreadLocal(ThreadLocal tl) { return tl == null ? null : tl.get(); } static A getThreadLocal(ThreadLocal tl, A defaultValue) { return or(getThreadLocal(tl), defaultValue); } static ThreadLocal print_byThread_dontCreate() { return print_byThread; } static boolean isFalse(Object o) { return eq(false, o); } static String getStackTrace(Throwable throwable) { lastException(throwable); return getStackTrace_noRecord(throwable); } static String getStackTrace_noRecord(Throwable throwable) { StringWriter writer = new StringWriter(); throwable.printStackTrace(new PrintWriter(writer)); return hideCredentials(writer.toString()); } static String getStackTrace() { return getStackTrace_noRecord(new Throwable()); } static String getStackTrace(String msg) { return getStackTrace_noRecord(new Throwable(msg)); } static String fixNewLines(String s) { int i = indexOf(s, '\r'); if (i < 0) return s; int l = s.length(); StringBuilder out = new StringBuilder(l); out.append(s, 0, i); for (; i < l; i++) { char c = s.charAt(i); if (c != '\r') out.append(c); else { out.append('\n'); if (i+1 < l && s.charAt(i+1) == '\n') ++i; } } return out.toString(); } static void print_append(Appendable buf, String s, int max) { try { synchronized(buf) { buf.append(s); if (buf instanceof StringBuffer) rotateStringBuffer(((StringBuffer) buf), max); else if (buf instanceof StringBuilder) rotateStringBuilder(((StringBuilder) buf), max); } } catch (Exception __e) { throw rethrow(__e); } } static Class mc() { return main.class; } static List _registerWeakMap_preList; static A _registerWeakMap(A map) { if (javax() == null) { // We're in class init if (_registerWeakMap_preList == null) _registerWeakMap_preList = synchroList(); _registerWeakMap_preList.add(map); return map; } try { call(javax(), "_registerWeakMap", map); } catch (Throwable e) { printException(e); print("Upgrade JavaX!!"); } return map; } static void _onLoad_registerWeakMap() { assertNotNull(javax()); if (_registerWeakMap_preList == null) return; for (Object o : _registerWeakMap_preList) _registerWeakMap(o); _registerWeakMap_preList = null; } static x30_pkg.x30_util.BetterThreadLocal newPing_actionTL; static x30_pkg.x30_util.BetterThreadLocal newPing_actionTL() { if (newPing_actionTL == null) newPing_actionTL = vm_generalMap_getOrCreate("newPing_actionTL", () -> { Runnable value = (Runnable) (callF_gen(vm_generalMap_get("newPing_valueForNewThread"))); var tl = new x30_pkg.x30_util.BetterThreadLocal(); tl.set(value); return tl; }); return newPing_actionTL; } static int isAndroid_flag; static boolean isAndroid() { if (isAndroid_flag == 0) isAndroid_flag = System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0 ? 1 : -1; return isAndroid_flag > 0; } static Boolean isHeadless_cache; static boolean isHeadless() { if (isHeadless_cache != null) return isHeadless_cache; if (isAndroid()) return isHeadless_cache = true; if (GraphicsEnvironment.isHeadless()) return isHeadless_cache = true; // Also check if AWT actually works. // If DISPLAY variable is set but no X server up, this will notice. try { SwingUtilities.isEventDispatchThread(); return isHeadless_cache = false; } catch (Throwable e) { return isHeadless_cache = true; } } static volatile boolean licensed_yes = true; static boolean licensed() { if (!licensed_yes) return false; ping_okInCleanUp(); return true; } static void licensed_off() { licensed_yes = false; } static String unnull(String s) { return s == null ? "" : s; } static Collection unnull(Collection l) { return l == null ? emptyList() : l; } static List unnull(List l) { return l == null ? emptyList() : l; } static int[] unnull(int[] l) { return l == null ? emptyIntArray() : l; } static char[] unnull(char[] l) { return l == null ? emptyCharArray() : l; } static double[] unnull(double[] l) { return l == null ? emptyDoubleArray() : l; } static Map unnull(Map l) { return l == null ? emptyMap() : l; } static Iterable unnull(Iterable i) { return i == null ? emptyList() : i; } static A[] unnull(A[] a) { return a == null ? (A[]) emptyObjectArray() : a; } static BitSet unnull(BitSet b) { return b == null ? new BitSet() : b; } //ifclass Symbol static Symbol unnull(Symbol s) { return s == null ? emptySymbol() : s; } //endif static Pair unnull(Pair p) { return p != null ? p : new Pair(null, null); } static int unnull(Integer i) { return i == null ? 0 : i; } static long unnull(Long l) { return l == null ? 0L : l; } static double unnull(Double l) { return l == null ? 0.0 : l; } static String strOrNull(Object o) { return o == null ? null : str(o); } static boolean nempty(Collection c) { return !empty(c); } static boolean nempty(CharSequence s) { return !empty(s); } static boolean nempty(Object[] o) { return !empty(o); } static boolean nempty(byte[] o) { return !empty(o); } static boolean nempty(int[] o) { return !empty(o); } static boolean nempty(BitSet bs) { return !empty(bs); } static boolean nempty(Map m) { return !empty(m); } static boolean nempty(Iterator i) { return i != null && i.hasNext(); } static boolean nempty(MultiMap mm) { return mm != null && !mm.isEmpty(); } static boolean nempty(Object o) { return !empty(o); } static ArrayList cloneList(Iterable l) { return l instanceof Collection ? cloneList((Collection) l) : asList(l); } static ArrayList cloneList(Collection l) { if (l == null) return new ArrayList(); synchronized(collectionMutex(l)) { return new ArrayList(l); } } static Object pcallF_minimalExceptionHandling(Object f, Object... args) { try { return callFunction(f, args); } catch (Throwable e) { System.out.println(getStackTrace(e)); _storeException(e); } return null; } static Set vm_generalIdentityHashSet(Object name) { synchronized(vm_generalMap()) { Set set = (Set) (vm_generalMap_get(name)); if (set == null) vm_generalMap_put(name, set = syncIdentityHashSet()); return set; } } static Map vm_generalHashMap(Object name) { synchronized(vm_generalMap()) { Map m = (Map) (vm_generalMap_get(name)); if (m == null) vm_generalMap_put(name, m = syncHashMap()); return m; } } static Class __javax; static Class getJavaX() { try { return __javax; } catch (Exception __e) { throw rethrow(__e); } } static void __setJavaX(Class j) { __javax = j; _onJavaXSet(); } static boolean methodIsStatic(Method m) { return (m.getModifiers() & Modifier.STATIC) != 0; } static boolean argumentCompatibleWithType(Object arg, Class type) { return arg == null ? !type.isPrimitive() : isInstanceX(type, arg); } static void arraycopy(Object[] a, Object[] b) { if (a != null && b != null) arraycopy(a, 0, b, 0, Math.min(a.length, b.length)); } static void arraycopy(Object src, int srcPos, int destPos, int n) { arraycopy(src, srcPos, src, destPos, n); } static void arraycopy(Object src, int srcPos, Object dest, int destPos, int n) { if (n != 0) System.arraycopy(src, srcPos, dest, destPos, n); } static A[] arrayOfType(Class type, int n) { return makeArray(type, n); } static A[] arrayOfType(int n, Class type) { return arrayOfType(type, n); } static List allToString(Iterable c) { List l = new ArrayList(); for (Object o : unnull(c)) l.add(str(o)); return l; } static List allToString(Object[] c) { List l = new ArrayList(); for (Object o : unnull(c)) l.add(str(o)); return l; } // binary legacy signature static Object[] toObjectArray(Collection c) { return toObjectArray((Iterable) c); } static Object[] toObjectArray(Iterable c) { List l = asList(c); return l.toArray(new Object[l.size()]); } static ThreadLocal print_byThread() { synchronized(print_byThread_lock) { if (print_byThread == null) print_byThread = new ThreadLocal(); } return print_byThread; } // f can return false to suppress regular printing // call print_raw within f to actually print something static AutoCloseable tempInterceptPrint(F1 f) { return tempSetThreadLocal(print_byThread(), f); } static List getClasses(Object[] array) { List l = emptyList(l(array)); for (Object o : array) l.add(_getClass(o)); return l; } static void multiMapPut(Map> map, A a, B b) { List l = map.get(a); if (l == null) map.put(a, l = new ArrayList()); l.add(b); } static void multiMapPut(MultiMap mm, A key, B value) { if (mm != null && key != null && value != null) mm.put(key, value); } static Map synchronizedMap() { return synchroMap(); } static Map synchronizedMap(Map map) { return synchroMap(map); } static boolean endsWithLetterOrDigit(String s) { return s != null && s.length() > 0 && Character.isLetterOrDigit(s.charAt(s.length()-1)); } static Object getOpt(Object o, String field) { return getOpt_cached(o, field); } static Object getOpt(String field, Object o) { return getOpt_cached(o, field); } static Object getOpt_raw(Object o, String field) { try { Field f = getOpt_findField(o.getClass(), field); if (f == null) return null; makeAccessible(f); return f.get(o); } catch (Exception __e) { throw rethrow(__e); } } // access of static fields is not yet optimized static Object getOpt(Class c, String field) { try { if (c == null) return null; Field f = getOpt_findStaticField(c, field); if (f == null) return null; makeAccessible(f); return f.get(null); } catch (Exception __e) { throw rethrow(__e); } } static Field getOpt_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); return null; } // PersistableThrowable doesn't hold GC-disturbing class references in backtrace static volatile PersistableThrowable lastException_lastException; static PersistableThrowable lastException() { return lastException_lastException; } static void lastException(Throwable e) { lastException_lastException = persistableThrowable(e); } static String hideCredentials(URL url) { return url == null ? null : hideCredentials(str(url)); } static String hideCredentials(String url) { try { if (startsWithOneOf(url, "http://", "https://") && isAGIBlueDomain(hostNameFromURL(url))) return url; } catch (Throwable e) { print("HideCredentials", e); } return url.replaceAll("([&?])(_pass|key|cookie)=[^&\\s\"]*", "$1$2="); } static String hideCredentials(Object o) { return hideCredentials(str(o)); } static int indexOf(List l, A a, int startIndex) { if (l == null) return -1; int n = l(l); for (int i = startIndex; i < n; i++) if (eq(l.get(i), a)) return i; return -1; } static int indexOf(List l, int startIndex, A a) { return indexOf(l, a, startIndex); } static int indexOf(List l, A a) { if (l == null) return -1; return l.indexOf(a); } static int indexOf(String a, String b) { return a == null || b == null ? -1 : a.indexOf(b); } static int indexOf(String a, String b, int i) { return a == null || b == null ? -1 : a.indexOf(b, i); } static int indexOf(String a, char b) { return a == null ? -1 : a.indexOf(b); } static int indexOf(String a, int i, char b) { return indexOf(a, b, i); } static int indexOf(String a, char b, int i) { return a == null ? -1 : a.indexOf(b, i); } static int indexOf(String a, int i, String b) { return a == null || b == null ? -1 : a.indexOf(b, i); } static int indexOf(A[] x, A a) { int n = l(x); for (int i = 0; i < n; i++) if (eq(x[i], a)) return i; return -1; } static void rotateStringBuffer(StringBuffer buf, int max) { try { if (buf == null) return; synchronized(buf) { if (buf.length() <= max) return; try { int newLength = max/2; int ofs = buf.length()-newLength; String newString = buf.substring(ofs); buf.setLength(0); buf.append("[...] ").append(newString); } catch (Exception e) { buf.setLength(0); } buf.trimToSize(); } } catch (Exception __e) { throw rethrow(__e); } } static void rotateStringBuilder(StringBuilder buf, int max) { try { if (buf == null) return; synchronized(buf) { if (buf.length() <= max) return; try { int newLength = max/2; int ofs = buf.length()-newLength; String newString = buf.substring(ofs); buf.setLength(0); buf.append("[...] ").append(newString); } catch (Exception e) { buf.setLength(0); } buf.trimToSize(); } } catch (Exception __e) { throw rethrow(__e); } } static A printException(A e) { printStackTrace(e); return e; } static A vm_generalMap_getOrCreate(Object key, F0 create) { return vm_generalMap_getOrCreate(key, f0ToIF0(create)); } static A vm_generalMap_getOrCreate(Object key, IF0 create) { Map generalMap = vm_generalMap(); if (generalMap == null) return null; // must be x30 init synchronized(generalMap) { // should switch to locks here A a = (A) (vm_generalMap_get(key)); if (a == null) vm_generalMap_put(key, a = create == null ? null : create.get()); return a; } } static A callF_gen(F0 f) { return f == null ? null : f.get(); } static B callF_gen(F1 f, A a) { return f == null ? null : f.get(a); } static A callF_gen(IF0 f) { return f == null ? null : f.get(); } static B callF_gen(IF1 f, A a) { return f == null ? null : f.get(a); } static B callF_gen(A a, IF1 f) { return f == null ? null : f.get(a); } static C callF_gen(IF2 f, A a, B b) { return f == null ? null : f.get(a, b); } static void callF_gen(VF1 f, A a) { { if (f != null) f.get(a); } } static void callF_gen(A a, IVF1 f) { { if (f != null) f.get(a); } } static void callF_gen(IVF1 f, A a) { { if (f != null) f.get(a); } } static Object callF_gen(Runnable r) { { if (r != null) r.run(); } return null; } static Object callF_gen(Object f, Object... args) { return callF(f, args); } static Object vm_generalMap_get(Object key) { return vm_generalMap().get(key); } static Map emptyMap() { return new HashMap(); } // TODO: JDK 17!! ?? No! Yes? Yes!! static Object collectionMutex(List l) { return l; } static Object collectionMutex(Object o) { if (o instanceof List) return o; String c = className(o); if (eq(c, "java.util.TreeMap$KeySet")) c = className(o = getOpt(o, "m")); else if (eq(c, "java.util.HashMap$KeySet")) c = className(o = get_raw(o, "this$0")); if (eqOneOf(c, "java.util.TreeMap$AscendingSubMap", "java.util.TreeMap$DescendingSubMap")) c = className(o = get_raw(o, "m")); return o; } static Object callFunction(Object f, Object... args) { return callF(f, args); } static Throwable _storeException_value; static void _storeException(Throwable e) { _storeException_value = e; } static Map vm_generalMap_map; static Map vm_generalMap() { if (vm_generalMap_map == null) vm_generalMap_map = (Map) get(javax(), "generalMap"); return vm_generalMap_map; } static Object vm_generalMap_put(Object key, Object value) { return mapPutOrRemove(vm_generalMap(), key, value); } static Set syncIdentityHashSet() { return (Set) synchronizedSet(identityHashSet()); } static Map syncHashMap() { return synchroHashMap(); } static void _onJavaXSet() {} static A[] makeArray(Class type, int n) { return (A[]) Array.newInstance(type, n); } static AutoCloseable tempSetThreadLocal(final ThreadLocal tl, A a) { if (tl == null) return null; final A prev = setThreadLocal(tl, a); return new AutoCloseable() { public String toString() { return "tl.set(prev);"; } public void close() throws Exception { tl.set(prev); }}; } static Class _getClass(String name) { try { return Class.forName(name); } catch (ClassNotFoundException e) { return null; // could optimize this } } static Class _getClass(Object o) { return o == null ? null : o instanceof Class ? (Class) o : o.getClass(); } static Class _getClass(Object realm, String name) { try { return classLoaderForObject(realm).loadClass(classNameToVM(name)); } catch (ClassNotFoundException e) { return null; // could optimize this } } //static final Map> getOpt_cache = newDangerousWeakHashMap(f getOpt_special_init); static class getOpt_Map extends WeakHashMap { getOpt_Map() { if (getOpt_special == null) getOpt_special = new HashMap(); clear(); } public void clear() { super.clear(); //print("getOpt clear"); put(Class.class, getOpt_special); put(String.class, getOpt_special); } } static final Map> getOpt_cache = _registerDangerousWeakMap(synchroMap(new getOpt_Map())); //static final Map> getOpt_cache = _registerWeakMap(synchroMap(new getOpt_Map)); static HashMap getOpt_special; // just a marker /*static void getOpt_special_init(Map map) { map.put(Class.class, getOpt_special); map.put(S.class, getOpt_special); }*/ static Map getOpt_getFieldMap(Object o) { Class c = _getClass(o); HashMap map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); return map; } static Object getOpt_cached(Object o, String field) { try { if (o == null) return null; Map map = getOpt_getFieldMap(o); if (map == getOpt_special) { if (o instanceof Class) return getOpt((Class) o, field); /*if (o instanceof S) ret getOpt(getBot((S) o), field);*/ if (o instanceof Map) return ((Map) o).get(field); } Field f = map.get(field); if (f != null) return f.get(o); if (o instanceof DynamicObject) return syncMapGet2(((DynamicObject) o).fieldValues, field); return null; } catch (Exception __e) { throw rethrow(__e); } } // used internally - we are in synchronized block static HashMap getOpt_makeCache(Class c) { HashMap map; if (isSubtypeOf(c, Map.class)) map = getOpt_special; else { map = new HashMap(); if (!reflection_classesNotToScan().contains(c.getName())) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) { makeAccessible(f); String name = f.getName(); if (!map.containsKey(name)) map.put(name, f); } _c = _c.getSuperclass(); } while (_c != null); } } if (getOpt_cache != null) getOpt_cache.put(c, map); return map; } static PersistableThrowable persistableThrowable(Throwable e) { return e == null ? null : new PersistableThrowable(e); } static boolean startsWithOneOf(String s, String... l) { for (String x : l) if (startsWith(s, x)) return true; return false; } static boolean startsWithOneOf(String s, Matches m, String... l) { for (String x : l) if (startsWith(s, x, m)) return true; return false; } static boolean isAGIBlueDomain(String domain) { return domainIsUnder(domain, theAGIBlueDomain()); } static String hostNameFromURL(String url) { try { return empty(url) ? null : new URL(url).getHost(); } catch (Exception __e) { throw rethrow(__e); } } static A printStackTrace(A e) { // we go to system.out now - system.err is nonsense if (e != null) print(getStackTrace(e)); return e; } static void printStackTrace() { printStackTrace(new Throwable()); } static void printStackTrace(String msg) { printStackTrace(new Throwable(msg)); } static void printStackTrace(String msg, Throwable e) { printStackTrace(new Throwable(msg, e)); } static IF0 f0ToIF0(F0 f) { return f == null ? null : () -> f.get(); } static String className(Object o) { return getClassName(o); } static boolean eqOneOf(Object o, Object... l) { for (Object x : l) if (eq(o, x)) return true; return false; } static B mapPutOrRemove(Map map, A key, B value) { if (map != null && key != null) if (value != null) return map.put(key, value); else return map.remove(key); return null; } static Set synchronizedSet() { return synchroHashSet(); } static Set synchronizedSet(Set set) { return Collections.synchronizedSet(set); } static Set identityHashSet() { return Collections.newSetFromMap(new IdentityHashMap()); } static A setThreadLocal(ThreadLocal tl, A value) { if (tl == null) return null; A old = tl.get(); tl.set(value); return old; } static ClassLoader classLoaderForObject(Object o) { if (o instanceof ClassLoader) return ((ClassLoader) o); if (o == null) return null; return _getClass(o).getClassLoader(); } // Note: This is actually broken. Inner classes must stay with a $ separator static String classNameToVM(String name) { return name.replace(".", "$"); } static void clear(Collection c) { if (c != null) c.clear(); } static void clear(Map map) { if (map != null) map.clear(); } static void put(Map map, A a, B b) { if (map != null) map.put(a, b); } static void put(List l, int i, A a) { if (l != null && i >= 0 && i < l(l)) l.set(i, a); } static B syncMapGet2(Map map, A a) { if (map == null) return null; synchronized(collectionMutex(map)) { return map.get(a); } } static B syncMapGet2(A a, Map map) { return syncMapGet2(map, a); } static boolean isSubtypeOf(Class a, Class b) { return a != null && b != null && b.isAssignableFrom(a); // << always hated that method, let's replace it! } static Set reflection_classesNotToScan_value = litset( "jdk.internal.loader.URLClassPath" ); static Set reflection_classesNotToScan() { return reflection_classesNotToScan_value; } static boolean startsWith(String a, String b) { return a != null && a.startsWith(unnull(b)); } static boolean startsWith(String a, char c) { return nemptyString(a) && a.charAt(0) == c; } static boolean startsWith(String a, String b, Matches m) { if (!startsWith(a, b)) return false; if (m != null) m.m = new String[] {substring(a, strL(b))}; return true; } static boolean startsWith(List a, List b) { if (a == null || listL(b) > listL(a)) return false; for (int i = 0; i < listL(b); i++) if (neq(a.get(i), b.get(i))) return false; return true; } static boolean domainIsUnder(String domain, String mainDomain) { return eqic(domain, mainDomain) || ewic(domain, "." + mainDomain); } static String theAGIBlueDomain() { return "agi.blue"; } static Set synchroHashSet() { return synchronizedSet(new HashSet()); } static HashSet litset(A... items) { return lithashset(items); } static boolean nemptyString(String s) { return s != null && s.length() > 0; } static String substring(String s, int x) { return substring(s, x, strL(s)); } static String substring(String s, int x, int y) { if (s == null) return null; if (x < 0) x = 0; int n = s.length(); if (y < x) y = x; if (y > n) y = n; if (x >= y) return ""; return s.substring(x, y); } // convenience method for quickly dropping a prefix static String substring(String s, CharSequence l) { return substring(s, lCharSequence(l)); } static int listL(Collection l) { return l == null ? 0 : l.size(); } static boolean neq(Object a, Object b) { return !eq(a, b); } static boolean ewic(String a, String b) { return endsWithIgnoreCase(a, b); } static boolean ewic(String a, String b, Matches m) { return endsWithIgnoreCase(a, b, m); } static HashSet lithashset(A... items) { HashSet set = new HashSet(); for (A a : items) set.add(a); return set; } static int lCharSequence(CharSequence s) { return s == null ? 0 : s.length(); } static boolean endsWithIgnoreCase(String a, String b) { int la = l(a), lb = l(b); return la >= lb && regionMatchesIC(a, la-lb, b, 0, lb); } static boolean endsWithIgnoreCase(String a, String b, Matches m) { if (!endsWithIgnoreCase(a, b)) return false; if (m != null) m.m = new String[] { substring(a, 0, l(a)-l(b)) }; return true; } static boolean regionMatchesIC(String a, int offsetA, String b, int offsetB, int len) { return a != null && a.regionMatches(true, offsetA, b, offsetB, len); } // immutable, has strong refs // Do not run in a synchronized block - it goes wrong in the presence // of elaborate classloaders (like in Gazelle BEA) // see #1102990 and #1102991 final static class _MethodCache { final Class c; final HashMap> cache = new HashMap(); _MethodCache(Class c) { this.c = c; _init(); } void _init() { Class _c = c; while (_c != null) { for (Method m : _c.getDeclaredMethods()) if (!isAbstract(m) && !reflection_isForbiddenMethod(m)) multiMapPut(cache, m.getName(), makeAccessible(m)); _c = _c.getSuperclass(); } // add default methods - this might lead to a duplication // because the overridden method is also added, but it's not // a problem except for minimal performance loss. for (Class intf : allInterfacesImplementedBy(c)) for (Method m : intf.getDeclaredMethods()) if (m.isDefault() && !reflection_isForbiddenMethod(m)) multiMapPut(cache, m.getName(), makeAccessible(m)); } // Returns only matching methods Method findMethod(String method, Object[] args) { try { List m = cache.get(method); if (m == null) return null; int n = m.size(); for (int i = 0; i < n; i++) { Method me = m.get(i); if (call_checkArgs(me, args, false)) return me; } return null; } catch (Exception __e) { throw rethrow(__e); } } Method findStaticMethod(String method, Object[] args) { try { List m = cache.get(method); if (m == null) return null; int n = m.size(); for (int i = 0; i < n; i++) { Method me = m.get(i); if (isStaticMethod(me) && call_checkArgs(me, args, false)) return me; } return null; } catch (Exception __e) { throw rethrow(__e); } } } static abstract class VF1 implements IVF1 { public abstract void get(A a); } static class Matches { String[] m; Matches() {} Matches(String... m) { this.m = m;} String get(int i) { return i < m.length ? m[i] : null; } String unq(int i) { return unquote(get(i)); } String tlc(int i) { return unq(i).toLowerCase(); } boolean bool(int i) { return "true".equals(unq(i)); } String rest() { return m[m.length-1]; } // for matchStart int psi(int i) { return Integer.parseInt(unq(i)); } public String toString() { return "Matches(" + joinWithComma(quoteAll(asList(m))) + ")"; } public int hashCode() { return _hashCode(toList(m)); } public boolean equals(Object o) { return o instanceof Matches && arraysEqual(m, ((Matches) o).m); } } // for the version with MasterSymbol (used WAY back in "Smart Bot"!) see #1010608 static class Symbol implements CharSequence { String text; Symbol() {} Symbol(String text, boolean dummy) { this.text = text;} // weird signature to prevent accidental calling public int hashCode() { return _hashCode(text); } public String toString() { return text; } public boolean equals(Object o) { return this == o; } // implementation of CharSequence methods public int length() { return text.length(); } public char charAt(int index) { return text.charAt(index); } public CharSequence subSequence(int start, int end) { return text.substring(start, end); } } static abstract class F0 { abstract A get(); } static abstract class F1 { abstract B get(A a); } // you still need to implement hasNext() and next() static abstract class IterableIterator implements Iterator, Iterable { public Iterator iterator() { return this; } public void remove() { unsupportedOperation(); } } static class DateStructures { abstract static class SomeDate {} abstract static class SomeDateDate extends SomeDate {} // day or higher granularity abstract static class SomeTime extends SomeDate {} abstract static class SomeWeek extends SomeDateDate {} abstract static class DateProp extends SomeDate {} // proposition on a date, e.g. a date range // years static class Year extends SomeDateDate implements IFieldsToList, Transformable, Visitable{ int year; Year() {} Year(int year) { this.year = year;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + year + ")"; } public boolean equals(Object o) { if (!(o instanceof Year)) return false; Year __0 = (Year) o; return year == __0.year; } public int hashCode() { int h = 2751581; h = boostHashCombine(h, _hashCode(year)); return h; } public Object[] _fieldsToList() { return new Object[] {year}; } public Object transformUsing(IF1 f) { return new Year((int) f.get(year)); } public void visitUsing(IVF1 f) { f.get(year); } } static class CurrentYearPlus extends SomeDateDate implements IFieldsToList, Transformable, Visitable{ int nYears; CurrentYearPlus() {} CurrentYearPlus(int nYears) { this.nYears = nYears;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + nYears + ")"; } public boolean equals(Object o) { if (!(o instanceof CurrentYearPlus)) return false; CurrentYearPlus __1 = (CurrentYearPlus) o; return nYears == __1.nYears; } public int hashCode() { int h = -283479056; h = boostHashCombine(h, _hashCode(nYears)); return h; } public Object[] _fieldsToList() { return new Object[] {nYears}; } public Object transformUsing(IF1 f) { return new CurrentYearPlus((int) f.get(nYears)); } public void visitUsing(IVF1 f) { f.get(nYears); } } // months static class Month extends SomeDateDate implements IFieldsToList, Transformable, Visitable{ int month; Year year; Month() {} Month(int month, Year year) { this.year = year; this.month = month;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + month + ", " + year + ")"; } public boolean equals(Object o) { if (!(o instanceof Month)) return false; Month __2 = (Month) o; return month == __2.month && eq(year, __2.year); } public int hashCode() { int h = 74527328; h = boostHashCombine(h, _hashCode(month)); h = boostHashCombine(h, _hashCode(year)); return h; } public Object[] _fieldsToList() { return new Object[] {month, year}; } public Object transformUsing(IF1 f) { return new Month((int) f.get(month), (Year) f.get(year)); } public void visitUsing(IVF1 f) { f.get(month); f.get(year); } Month(int month) { this(month, null); } } static class CurrentMonthPlus extends SomeDateDate implements IFieldsToList, Transformable, Visitable{ int nMonths; CurrentMonthPlus() {} CurrentMonthPlus(int nMonths) { this.nMonths = nMonths;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + nMonths + ")"; } public boolean equals(Object o) { if (!(o instanceof CurrentMonthPlus)) return false; CurrentMonthPlus __3 = (CurrentMonthPlus) o; return nMonths == __3.nMonths; } public int hashCode() { int h = -1003838751; h = boostHashCombine(h, _hashCode(nMonths)); return h; } public Object[] _fieldsToList() { return new Object[] {nMonths}; } public Object transformUsing(IF1 f) { return new CurrentMonthPlus((int) f.get(nMonths)); } public void visitUsing(IVF1 f) { f.get(nMonths); } } // weeks static class Week extends SomeWeek implements IFieldsToList, Transformable, Visitable{ int week; Year year; Week() {} Week(int week, Year year) { this.year = year; this.week = week;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + week + ", " + year + ")"; } public boolean equals(Object o) { if (!(o instanceof Week)) return false; Week __4 = (Week) o; return week == __4.week && eq(year, __4.year); } public int hashCode() { int h = 2692116; h = boostHashCombine(h, _hashCode(week)); h = boostHashCombine(h, _hashCode(year)); return h; } public Object[] _fieldsToList() { return new Object[] {week, year}; } public Object transformUsing(IF1 f) { return new Week((int) f.get(week), (Year) f.get(year)); } public void visitUsing(IVF1 f) { f.get(week); f.get(year); } } static class CurrentWeekPlus extends SomeWeek implements IFieldsToList, Transformable, Visitable{ int nWeeks; CurrentWeekPlus() {} CurrentWeekPlus(int nWeeks) { this.nWeeks = nWeeks;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + nWeeks + ")"; } public boolean equals(Object o) { if (!(o instanceof CurrentWeekPlus)) return false; CurrentWeekPlus __5 = (CurrentWeekPlus) o; return nWeeks == __5.nWeeks; } public int hashCode() { int h = 633919527; h = boostHashCombine(h, _hashCode(nWeeks)); return h; } public Object[] _fieldsToList() { return new Object[] {nWeeks}; } public Object transformUsing(IF1 f) { return new CurrentWeekPlus((int) f.get(nWeeks)); } public void visitUsing(IVF1 f) { f.get(nWeeks); } } // days static class Day extends SomeDate implements IFieldsToList, Transformable, Visitable{ int day; Month month; Day() {} Day(int day, Month month) { this.month = month; this.day = day;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + day + ", " + month + ")"; } public boolean equals(Object o) { if (!(o instanceof Day)) return false; Day __6 = (Day) o; return day == __6.day && eq(month, __6.month); } public int hashCode() { int h = 68476; h = boostHashCombine(h, _hashCode(day)); h = boostHashCombine(h, _hashCode(month)); return h; } public Object[] _fieldsToList() { return new Object[] {day, month}; } public Object transformUsing(IF1 f) { return new Day((int) f.get(day), (Month) f.get(month)); } public void visitUsing(IVF1 f) { f.get(day); f.get(month); } } static class TodayPlus extends SomeDate implements IFieldsToList, Transformable, Visitable{ int nDays; TodayPlus() {} TodayPlus(int nDays) { this.nDays = nDays;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + nDays + ")"; } public boolean equals(Object o) { if (!(o instanceof TodayPlus)) return false; TodayPlus __7 = (TodayPlus) o; return nDays == __7.nDays; } public int hashCode() { int h = 123418715; h = boostHashCombine(h, _hashCode(nDays)); return h; } public Object[] _fieldsToList() { return new Object[] {nDays}; } public Object transformUsing(IF1 f) { return new TodayPlus((int) f.get(nDays)); } public void visitUsing(IVF1 f) { f.get(nDays); } } // weekdays static class Weekday extends SomeDateDate implements IFieldsToList, Transformable, Visitable{ int weekday; SomeWeek week; Weekday() {} Weekday(int weekday, SomeWeek week) { this.week = week; this.weekday = weekday;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + weekday + ", " + week + ")"; } public boolean equals(Object o) { if (!(o instanceof Weekday)) return false; Weekday __8 = (Weekday) o; return weekday == __8.weekday && eq(week, __8.week); } public int hashCode() { int h = -1403451640; h = boostHashCombine(h, _hashCode(weekday)); h = boostHashCombine(h, _hashCode(week)); return h; } public Object[] _fieldsToList() { return new Object[] {weekday, week}; } public Object transformUsing(IF1 f) { return new Weekday((int) f.get(weekday), (SomeWeek) f.get(week)); } public void visitUsing(IVF1 f) { f.get(weekday); f.get(week); } // weekday is in Java count (1=Sunday) Weekday(int weekday) { this.weekday = weekday; } } // hours static class Hour extends SomeTime implements IFieldsToList, Transformable, Visitable{ int hour; Boolean isPM; Day day; Hour() {} Hour(int hour, Boolean isPM, Day day) { this.day = day; this.isPM = isPM; this.hour = hour;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + hour + ", " + isPM + ", " + day + ")"; } public boolean equals(Object o) { if (!(o instanceof Hour)) return false; Hour __9 = (Hour) o; return hour == __9.hour && eq(isPM, __9.isPM) && eq(day, __9.day); } public int hashCode() { int h = 2255364; h = boostHashCombine(h, _hashCode(hour)); h = boostHashCombine(h, _hashCode(isPM)); h = boostHashCombine(h, _hashCode(day)); return h; } public Object[] _fieldsToList() { return new Object[] {hour, isPM, day}; } public Object transformUsing(IF1 f) { return new Hour((int) f.get(hour), (Boolean) f.get(isPM), (Day) f.get(day)); } public void visitUsing(IVF1 f) { f.get(hour); f.get(isPM); f.get(day); } Hour(int hour, Boolean isPM) { this(hour, isPM, null); } } static class CurrentHourPlus extends SomeTime implements IFieldsToList, Transformable, Visitable{ int nHours; CurrentHourPlus() {} CurrentHourPlus(int nHours) { this.nHours = nHours;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + nHours + ")"; } public boolean equals(Object o) { if (!(o instanceof CurrentHourPlus)) return false; CurrentHourPlus __10 = (CurrentHourPlus) o; return nHours == __10.nHours; } public int hashCode() { int h = 1011201559; h = boostHashCombine(h, _hashCode(nHours)); return h; } public Object[] _fieldsToList() { return new Object[] {nHours}; } public Object transformUsing(IF1 f) { return new CurrentHourPlus((int) f.get(nHours)); } public void visitUsing(IVF1 f) { f.get(nHours); } } // minutes static class Minute extends SomeTime implements IFieldsToList, Transformable, Visitable{ int minute; Hour hour; Minute() {} Minute(int minute, Hour hour) { this.hour = hour; this.minute = minute;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + minute + ", " + hour + ")"; } public boolean equals(Object o) { if (!(o instanceof Minute)) return false; Minute __11 = (Minute) o; return minute == __11.minute && eq(hour, __11.hour); } public int hashCode() { int h = -1990159820; h = boostHashCombine(h, _hashCode(minute)); h = boostHashCombine(h, _hashCode(hour)); return h; } public Object[] _fieldsToList() { return new Object[] {minute, hour}; } public Object transformUsing(IF1 f) { return new Minute((int) f.get(minute), (Hour) f.get(hour)); } public void visitUsing(IVF1 f) { f.get(minute); f.get(hour); } } static class CurrentMinutePlus extends SomeTime implements IFieldsToList, Transformable, Visitable{ int nMinutes; CurrentMinutePlus() {} CurrentMinutePlus(int nMinutes) { this.nMinutes = nMinutes;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + nMinutes + ")"; } public boolean equals(Object o) { if (!(o instanceof CurrentMinutePlus)) return false; CurrentMinutePlus __12 = (CurrentMinutePlus) o; return nMinutes == __12.nMinutes; } public int hashCode() { int h = -1844800505; h = boostHashCombine(h, _hashCode(nMinutes)); return h; } public Object[] _fieldsToList() { return new Object[] {nMinutes}; } public Object transformUsing(IF1 f) { return new CurrentMinutePlus((int) f.get(nMinutes)); } public void visitUsing(IVF1 f) { f.get(nMinutes); } } // seconds static class Second extends SomeTime implements IFieldsToList, Transformable, Visitable{ int second; Minute minute; Second() {} Second(int second, Minute minute) { this.minute = minute; this.second = second;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + second + ", " + minute + ")"; } public boolean equals(Object o) { if (!(o instanceof Second)) return false; Second __13 = (Second) o; return second == __13.second && eq(minute, __13.minute); } public int hashCode() { int h = -1822412652; h = boostHashCombine(h, _hashCode(second)); h = boostHashCombine(h, _hashCode(minute)); return h; } public Object[] _fieldsToList() { return new Object[] {second, minute}; } public Object transformUsing(IF1 f) { return new Second((int) f.get(second), (Minute) f.get(minute)); } public void visitUsing(IVF1 f) { f.get(second); f.get(minute); } } // special stuff static class BeginningOfTime extends SomeDate implements IFieldsToList, Transformable, Visitable{ BeginningOfTime() {} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + ")"; } public boolean equals(Object o) { return o instanceof BeginningOfTime; } public int hashCode() { int h = -1618841503; return h; } public Object[] _fieldsToList() { return null; } public Object transformUsing(IF1 f) { return this; } public void visitUsing(IVF1 f) { } } static class EndOfTime extends SomeDate implements IFieldsToList, Transformable, Visitable{ EndOfTime() {} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + ")"; } public boolean equals(Object o) { return o instanceof EndOfTime; } public int hashCode() { int h = -810134049; return h; } public Object[] _fieldsToList() { return null; } public Object transformUsing(IF1 f) { return this; } public void visitUsing(IVF1 f) { } } // date ranges & boolean operations static class Between extends DateProp implements IFieldsToList, Transformable, Visitable{ SomeDate from; SomeDate to; Between() {} Between(SomeDate from, SomeDate to) { this.to = to; this.from = from;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + from + ", " + to + ")"; } public boolean equals(Object o) { if (!(o instanceof Between)) return false; Between __14 = (Between) o; return eq(from, __14.from) && eq(to, __14.to); } public int hashCode() { int h = 1448018920; h = boostHashCombine(h, _hashCode(from)); h = boostHashCombine(h, _hashCode(to)); return h; } public Object[] _fieldsToList() { return new Object[] {from, to}; } public Object transformUsing(IF1 f) { return new Between((SomeDate) f.get(from), (SomeDate) f.get(to)); } public void visitUsing(IVF1 f) { f.get(from); f.get(to); } } static class Or extends DateProp implements IFieldsToList, Transformable, Visitable{ DateProp a; DateProp b; Or() {} Or(DateProp a, DateProp b) { this.b = b; this.a = a;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + a + ", " + b + ")"; } public boolean equals(Object o) { if (!(o instanceof Or)) return false; Or __15 = (Or) o; return eq(a, __15.a) && eq(b, __15.b); } public int hashCode() { int h = 2563; h = boostHashCombine(h, _hashCode(a)); h = boostHashCombine(h, _hashCode(b)); return h; } public Object[] _fieldsToList() { return new Object[] {a, b}; } public Object transformUsing(IF1 f) { return new Or((DateProp) f.get(a), (DateProp) f.get(b)); } public void visitUsing(IVF1 f) { f.get(a); f.get(b); } } static class And extends DateProp implements IFieldsToList, Transformable, Visitable{ DateProp a; DateProp b; And() {} And(DateProp a, DateProp b) { this.b = b; this.a = a;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + a + ", " + b + ")"; } public boolean equals(Object o) { if (!(o instanceof And)) return false; And __16 = (And) o; return eq(a, __16.a) && eq(b, __16.b); } public int hashCode() { int h = 65975; h = boostHashCombine(h, _hashCode(a)); h = boostHashCombine(h, _hashCode(b)); return h; } public Object[] _fieldsToList() { return new Object[] {a, b}; } public Object transformUsing(IF1 f) { return new And((DateProp) f.get(a), (DateProp) f.get(b)); } public void visitUsing(IVF1 f) { f.get(a); f.get(b); } } static class Not extends DateProp implements IFieldsToList, Transformable, Visitable{ DateProp a; Not() {} Not(DateProp a) { this.a = a;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + a + ")"; } public boolean equals(Object o) { if (!(o instanceof Not)) return false; Not __17 = (Not) o; return eq(a, __17.a); } public int hashCode() { int h = 78515; h = boostHashCombine(h, _hashCode(a)); return h; } public Object[] _fieldsToList() { return new Object[] {a}; } public Object transformUsing(IF1 f) { return new Not((DateProp) f.get(a)); } public void visitUsing(IVF1 f) { f.get(a); } } // some utility functions static boolean containsTimes(SomeDate d) { return defaultMetaTransformer().any(o -> o instanceof SomeTime, d); } static boolean containsDateDates(SomeDate d) { return defaultMetaTransformer().any(o -> o instanceof SomeDateDate, d); } } // result of a (partial) parse. combines a value and a token range in a tokenization // Good for bottom-up parsing // See pwt_initial and EnglishDateParser static class ParsedWithTokens extends Var { List tok; // full CNC token list being parsed int iStart; // points to first parsed C token int iRemaining; // points to first unparsed C token ParsedWithTokens() {} ParsedWithTokens(A a) { super(a); } ParsedWithTokens(A a, List tok, int iStart, int iRemaining) { super(a); this.iRemaining = iRemaining; this.iStart = iStart; this.tok = tok; } String parsedText() { return joinSubList(tok, iStart | 1, iRemaining & ~1); } ListAndIndex remaining() { return new ListAndIndex(tok, iRemaining); } ListAndIndex start() { return new ListAndIndex(tok, iStart); } int length() { return iRemaining-iStart; } ParsedWithTokens withValue(B b) { return new ParsedWithTokens(b, tok, iStart, iRemaining); } public String toString() { return "Parsed " + quote(parsedText()) + " as " + super.toString(); } void replaceTokens(String s) { main.replaceTokens(tok, iStart, iRemaining, s); } } static class MultiMap { Map> data = new HashMap>(); int fullSize; MultiMap() {} MultiMap(boolean useTreeMap) { if (useTreeMap) data = new TreeMap(); } MultiMap(MultiMap map) { putAll(map); } MultiMap(Map> data) { this.data = data;} void put(A key, B value) { synchronized(data) { List list = data.get(key); if (list == null) data.put(key, list = _makeEmptyList()); list.add(value); ++fullSize; }} void add(A key, B value) { put(key, value); } void addAll(A key, Collection values) { putAll(key, values); } void addAllIfNotThere(A key, Collection values) { synchronized(data) { for (B value : values) setPut(key, value); }} void setPut(A key, B value) { synchronized(data) { if (!containsPair(key, value)) put(key, value); }} boolean containsPair(A key, B value) { synchronized(data) { return get(key).contains(value); }} void putAll(Collection keys, B value) { synchronized(data) { for (A key : unnullForIteration(keys)) put(key, value); }} void putAll(A key, Collection values) { synchronized(data) { if (nempty(values)) getActual(key).addAll(values); }} void putAll(Iterable> pairs) { synchronized(data) { for (Pair p : unnullForIteration(pairs)) put(p.a, p.b); }} void removeAll(A key, Collection values) { synchronized(data) { for (B value : values) remove(key, value); }} List get(A key) { synchronized(data) { List list = data.get(key); return list == null ? Collections. emptyList() : list; }} List getOpt(A key) { synchronized(data) { return data.get(key); }} List getAndClear(A key) { synchronized(data) { List l = cloneList(data.get(key)); remove(key); return l; }} // returns actual mutable live list // creates the list if not there List getActual(A key) { synchronized(data) { List list = data.get(key); if (list == null) data.put(key, list = _makeEmptyList()); return list; }} void clean(A key) { synchronized(data) { List list = data.get(key); if (list != null && list.isEmpty()) { fullSize -= l(list); data.remove(key); } }} Set keySet() { synchronized(data) { return data.keySet(); }} Set keys() { synchronized(data) { return data.keySet(); }} void remove(A key) { synchronized(data) { fullSize -= l(this.getOpt(key)); data.remove(key); }} final void remove(Pair p){ removePair(p); } void removePair(Pair p) { if (p != null) remove(p.a, p.b); } void remove(A key, B value) { synchronized(data) { List list = data.get(key); if (list != null) { if (list.remove(value)) fullSize--; if (list.isEmpty()) data.remove(key); } }} void clear() { synchronized(data) { data.clear(); }} boolean containsKey(A key) { synchronized(data) { return data.containsKey(key); }} B getFirst(A key) { synchronized(data) { List list = get(key); return list.isEmpty() ? null : list.get(0); }} void addAll(MultiMap map) { putAll(map); } void putAll(MultiMap map) { synchronized(data) { for (A key : map.keySet()) putAll(key, map.get(key)); }} void putAll(Map map) { synchronized(data) { if (map != null) for (Map.Entry e : map.entrySet()) put(e.getKey(), e.getValue()); }} final int keyCount(){ return keysSize(); } int keysSize() { synchronized(data) { return l(data); }} // full size - note: expensive operation final int fullSize(){ return size(); } int size() { synchronized(data) { return fullSize; }} // expensive operation List reverseGet(B b) { synchronized(data) { List l = new ArrayList(); for (A key : data.keySet()) if (data.get(key).contains(b)) l.add(key); return l; }} Map> asMap() { synchronized(data) { return cloneMap(data); }} boolean isEmpty() { synchronized(data) { return data.isEmpty(); }} // override in subclasses List _makeEmptyList() { return new ArrayList(); } // returns live lists Collection> allLists() { synchronized(data) { return new ArrayList(data.values()); } } Collection> values() { return allLists(); } List allValues() { return concatLists(data.values()); } Object mutex() { return data; } public String toString() { return "mm" + str(data); } } static interface IF0 { A get(); } static interface Hasher { int hashCode(A a); boolean equals(A a, A b); } static interface IF2 { C get(A a, B b); } static interface IF1 { B get(A a); } static interface IF3 { D get(A a, B b, C c); } static class ListAndIndex implements IFieldsToList{ static final String _fieldOrder = "list idx"; List list; int idx; ListAndIndex() {} ListAndIndex(List list, int idx) { this.idx = idx; this.list = list;} public boolean equals(Object o) { if (!(o instanceof ListAndIndex)) return false; ListAndIndex __1 = (ListAndIndex) o; return eq(list, __1.list) && idx == __1.idx; } public int hashCode() { int h = 276903961; h = boostHashCombine(h, _hashCode(list)); h = boostHashCombine(h, _hashCode(idx)); return h; } public Object[] _fieldsToList() { return new Object[] {list, idx}; } boolean atEnd() { return idx >= l(list); } A get() { return _get(list, idx); } int size() { return l(list); } public String toString() { return subList(list, 0, idx) + ", then " + subList(list, idx); } ListAndIndex plus(int ofs) { return new ListAndIndex(list, idx+ofs); } } /* * @(#)WeakHashMap.java 1.5 98/09/30 * * Copyright 1998 by Sun Microsystems, Inc., * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information"). You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Sun. */ // From https://github.com/mernst/plume-lib/blob/df0bfafc3c16848d88f4ea0ef3c8bf3367ae085e/java/src/plume/WeakHasherMap.java static final class WeakHasherMap extends AbstractMap implements Map { private Hasher hasher = null; /*@Pure*/ private boolean keyEquals(Object k1, Object k2) { return (hasher==null ? k1.equals(k2) : hasher.equals(k1, k2)); } /*@Pure*/ private int keyHashCode(Object k1) { return (hasher==null ? k1.hashCode() : hasher.hashCode(k1)); } // The WeakKey class can't be static because it depends on the hasher. // That in turn means that its methods can't be static. // However, I need to be able to call the methods such as create() that // were static in the original version of this code. // This finesses that. private /*@Nullable*/ WeakKey WeakKeyCreate(K k) { if (k == null) return null; else return new WeakKey(k); } private /*@Nullable*/ WeakKey WeakKeyCreate(K k, ReferenceQueue q) { if (k == null) return null; else return new WeakKey(k, q); } // Cannot be a static class: uses keyHashCode() and keyEquals() private final class WeakKey extends WeakReference { private int hash; /* Hashcode of key, stored here since the key may be tossed by the GC */ private WeakKey(K k) { super(k); hash = keyHashCode(k); } private /*@Nullable*/ WeakKey create(K k) { if (k == null) return null; else return new WeakKey(k); } private WeakKey(K k, ReferenceQueue q) { super(k, q); hash = keyHashCode(k); } private /*@Nullable*/ WeakKey create(K k, ReferenceQueue q) { if (k == null) return null; else return new WeakKey(k, q); } /* A WeakKey is equal to another WeakKey iff they both refer to objects that are, in turn, equal according to their own equals methods */ /*@Pure*/ @Override public boolean equals(/*@Nullable*/ Object o) { if (o == null) return false; // never happens if (this == o) return true; // This test is illegal because WeakKey is a generic type, // so use the getClass hack below instead. // if (!(o instanceof WeakKey)) return false; if (!(o.getClass().equals(WeakKey.class))) return false; Object t = this.get(); @SuppressWarnings("unchecked") Object u = ((WeakKey)o).get(); if ((t == null) || (u == null)) return false; if (t == u) return true; return keyEquals(t, u); } /*@Pure*/ @Override public int hashCode() { return hash; } } /* Hash table mapping WeakKeys to values */ private HashMap hash; /* Reference queue for cleared WeakKeys */ private ReferenceQueue queue = new ReferenceQueue(); /* Remove all invalidated entries from the map, that is, remove all entries whose keys have been discarded. This method should be invoked once by each public mutator in this class. We don't invoke this method in public accessors because that can lead to surprising ConcurrentModificationExceptions. */ @SuppressWarnings("unchecked") private void processQueue() { WeakKey wk; while ((wk = (WeakKey)queue.poll()) != null) { // unchecked cast hash.remove(wk); } } /* -- Constructors -- */ /** * Constructs a new, empty WeakHashMap with the given * initial capacity and the given load factor. * * @param initialCapacity the initial capacity of the * WeakHashMap * * @param loadFactor the load factor of the WeakHashMap * * @throws IllegalArgumentException If the initial capacity is less than * zero, or if the load factor is * nonpositive */ public WeakHasherMap(int initialCapacity, float loadFactor) { hash = new HashMap(initialCapacity, loadFactor); } /** * Constructs a new, empty WeakHashMap with the given * initial capacity and the default load factor, which is * 0.75. * * @param initialCapacity the initial capacity of the * WeakHashMap * * @throws IllegalArgumentException If the initial capacity is less than * zero */ public WeakHasherMap(int initialCapacity) { hash = new HashMap(initialCapacity); } /** * Constructs a new, empty WeakHashMap with the default * capacity and the default load factor, which is 0.75. */ public WeakHasherMap() { hash = new HashMap(); } /** * Constructs a new, empty WeakHashMap with the default * capacity and the default load factor, which is 0.75. * The WeakHashMap uses the specified hasher for hashing * keys and comparing them for equality. * @param h the Hasher to use when hashing values for this map */ public WeakHasherMap(Hasher h) { hash = new HashMap(); hasher = h; } /* -- Simple queries -- */ /** * Returns the number of key-value mappings in this map. * Note: In contrast to most implementations of the * Map interface, the time required by this operation is * linear in the size of the map. */ /*@Pure*/ @Override public int size() { return entrySet().size(); } /** * Returns true if this map contains no key-value mappings. */ /*@Pure*/ @Override public boolean isEmpty() { return entrySet().isEmpty(); } /** * Returns true if this map contains a mapping for the * specified key. * * @param key the key whose presence in this map is to be tested */ /*@Pure*/ @Override public boolean containsKey(Object key) { @SuppressWarnings("unchecked") K kkey = (K) key; return hash.containsKey(WeakKeyCreate(kkey)); } /* -- Lookup and modification operations -- */ /** * Returns the value to which this map maps the specified key. * If this map does not contain a value for this key, then return * null. * * @param key the key whose associated value, if any, is to be returned */ /*@Pure*/ @Override public /*@Nullable*/ V get(Object key) { // type of argument is Object, not K @SuppressWarnings("unchecked") K kkey = (K) key; return hash.get(WeakKeyCreate(kkey)); } /** * Updates this map so that the given key maps to the given * value. If the map previously contained a mapping for * key then that mapping is replaced and the previous value is * returned. * * @param key the key that is to be mapped to the given * value * @param value the value to which the given key is to be * mapped * * @return the previous value to which this key was mapped, or * null if if there was no mapping for the key */ @Override public V put(K key, V value) { processQueue(); return hash.put(WeakKeyCreate(key, queue), value); } /** * Removes the mapping for the given key from this map, if * present. * * @param key the key whose mapping is to be removed * * @return the value to which this key was mapped, or null if * there was no mapping for the key */ @Override public V remove(Object key) { // type of argument is Object, not K processQueue(); @SuppressWarnings("unchecked") K kkey = (K) key; return hash.remove(WeakKeyCreate(kkey)); } /** * Removes all mappings from this map. */ @Override public void clear() { processQueue(); hash.clear(); } /* -- Views -- */ /* Internal class for entries */ // This can't be static, again because of dependence on hasher. @SuppressWarnings("TypeParameterShadowing") private final class Entry implements Map.Entry { private Map.Entry ent; private K key; /* Strong reference to key, so that the GC will leave it alone as long as this Entry exists */ Entry(Map.Entry ent, K key) { this.ent = ent; this.key = key; } /*@Pure*/ @Override public K getKey() { return key; } /*@Pure*/ @Override public V getValue() { return ent.getValue(); } @Override public V setValue(V value) { return ent.setValue(value); } /*@Pure*/ private boolean keyvalEquals(K o1, K o2) { return (o1 == null) ? (o2 == null) : keyEquals(o1, o2); } /*@Pure*/ private boolean valEquals(V o1, V o2) { return (o1 == null) ? (o2 == null) : o1.equals(o2); } /*@Pure*/ @SuppressWarnings("NonOverridingEquals") public boolean equals(Map.Entry e /* Object o*/) { // if (! (o instanceof Map.Entry)) return false; // Map.Entry e = (Map.Entry)o; return (keyvalEquals(key, e.getKey()) && valEquals(getValue(), e.getValue())); } /*@Pure*/ @Override public int hashCode() { V v; return (((key == null) ? 0 : keyHashCode(key)) ^ (((v = getValue()) == null) ? 0 : v.hashCode())); } } /* Internal class for entry sets */ private final class EntrySet extends AbstractSet> { Set> hashEntrySet = hash.entrySet(); @Override public Iterator> iterator() { return new Iterator>() { Iterator> hashIterator = hashEntrySet.iterator(); Map.Entry next = null; @Override public boolean hasNext() { while (hashIterator.hasNext()) { Map.Entry ent = hashIterator.next(); WeakKey wk = ent.getKey(); K k = null; if ((wk != null) && ((k = wk.get()) == null)) { /* Weak key has been cleared by GC */ continue; } next = new Entry(ent, k); return true; } return false; } @Override public Map.Entry next() { if ((next == null) && !hasNext()) throw new NoSuchElementException(); Map.Entry e = next; next = null; return e; } @Override public void remove() { hashIterator.remove(); } }; } /*@Pure*/ @Override public boolean isEmpty() { return !(iterator().hasNext()); } /*@Pure*/ @Override public int size() { int j = 0; for (Iterator> i = iterator(); i.hasNext(); i.next()) j++; return j; } @Override public boolean remove(Object o) { processQueue(); if (!(o instanceof Map.Entry)) return false; @SuppressWarnings("unchecked") Map.Entry e = (Map.Entry)o; // unchecked cast Object ev = e.getValue(); WeakKey wk = WeakKeyCreate(e.getKey()); Object hv = hash.get(wk); if ((hv == null) ? ((ev == null) && hash.containsKey(wk)) : hv.equals(ev)) { hash.remove(wk); return true; } return false; } /*@Pure*/ @Override public int hashCode() { int h = 0; for (Iterator> i = hashEntrySet.iterator(); i.hasNext(); ) { Map.Entry ent = i.next(); WeakKey wk = ent.getKey(); Object v; if (wk == null) continue; h += (wk.hashCode() ^ (((v = ent.getValue()) == null) ? 0 : v.hashCode())); } return h; } } private /*@Nullable*/ Set> entrySet = null; /** * Returns a Set view of the mappings in this map. */ /*@SideEffectFree*/ @Override public Set> entrySet() { if (entrySet == null) entrySet = new EntrySet(); return entrySet; } // find matching key K findKey(Object key) { processQueue(); K kkey = (K) key; // TODO: use replacement for HashMap to avoid reflection WeakKey wkey = WeakKeyCreate(kkey); WeakKey found = hashMap_findKey(hash, wkey); return found == null ? null : found.get(); } } static class PersistableThrowable extends DynamicObject { String className; String msg; String stacktrace; PersistableThrowable() {} PersistableThrowable(Throwable e) { if (e == null) className = "Crazy Null Error"; else { className = getClassName(e).replace('/', '.'); msg = e.getMessage(); stacktrace = getStackTrace_noRecord(e); } } public String toString() { return nempty(msg) ? className + ": " + msg : className; } } static interface IVF1 { void get(A a); } static class Fail extends RuntimeException implements IFieldsToList{ Object[] objects; Fail() {} Fail(Object... objects) { this.objects = objects;}public Object[] _fieldsToList() { return new Object[] {objects}; } Fail(Throwable cause, Object... objects) { super(cause); this.objects = objects; } public String toString() { return joinNemptiesWithColon("Fail", commaCombine(getCause(), objects)); } } static class Pair implements Comparable> { A a; B b; Pair() {} Pair(A a, B b) { this.b = b; this.a = a;} public int hashCode() { return hashCodeFor(a) + 2*hashCodeFor(b); } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Pair)) return false; Pair t = (Pair) o; return eq(a, t.a) && eq(b, t.b); } public String toString() { return "<" + a + ", " + b + ">"; } public int compareTo(Pair p) { if (p == null) return 1; int i = ((Comparable) a).compareTo(p.a); if (i != 0) return i; return ((Comparable) b).compareTo(p.b); } } static class Not implements IFieldsToList, Transformable, Visitable{ A a; Not() {} Not(A a) { this.a = a;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + a + ")"; } public boolean equals(Object o) { if (!(o instanceof Not)) return false; Not __0 = (Not) o; return eq(a, __0.a); } public int hashCode() { int h = 78515; h = boostHashCombine(h, _hashCode(a)); return h; } public Object[] _fieldsToList() { return new Object[] {a}; } public Object transformUsing(IF1 f) { return new Not((A) f.get(a)); } public void visitUsing(IVF1 f) { f.get(a); } Boolean get(Object o) { return not((Boolean) callF(a, o)); } } static interface IFieldsToList { Object[] _fieldsToList(); } static class And implements IFieldsToList, Transformable, Visitable{ A a; A b; And() {} And(A a, A b) { this.b = b; this.a = a;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + a + ", " + b + ")"; } public boolean equals(Object o) { if (!(o instanceof And)) return false; And __0 = (And) o; return eq(a, __0.a) && eq(b, __0.b); } public int hashCode() { int h = 65975; h = boostHashCombine(h, _hashCode(a)); h = boostHashCombine(h, _hashCode(b)); return h; } public Object[] _fieldsToList() { return new Object[] {a, b}; } public Object transformUsing(IF1 f) { return new And((A) f.get(a), (A) f.get(b)); } public void visitUsing(IVF1 f) { f.get(a); f.get(b); } } static class Var implements IVar, ISetter { Var() {} Var(A v) { this.v = v;} A v; // you can access this directly if you use one thread public synchronized void set(A a) { if (v != a) { v = a; notifyAll(); } } public synchronized A get() { return v; } public synchronized boolean has() { return v != null; } public void clear() { set(null); } public String toString() { return str(this.get()); } } static interface Visitable { void visitUsing(IVF1 f); } static interface Transformable { Object transformUsing(IF1 f); } static interface ISetter { void set(A a); } static interface IVar extends IF0 { void set(A a); A get(); default boolean has() { return get() != null; } default void clear() { set(null); } } static boolean isAbstract(Class c) { return (c.getModifiers() & Modifier.ABSTRACT) != 0; } static boolean isAbstract(Method m) { return (m.getModifiers() & Modifier.ABSTRACT) != 0; } static boolean reflection_isForbiddenMethod(Method m) { return m.getDeclaringClass() == Object.class && eqOneOf(m.getName(), "finalize", "clone", "registerNatives"); } static Set allInterfacesImplementedBy(Class c) { if (c == null) return null; HashSet set = new HashSet(); allInterfacesImplementedBy_find(c, set); return set; } static void allInterfacesImplementedBy_find(Class c, Set set) { if (c.isInterface() && !set.add(c)) return; do { for (Class intf : c.getInterfaces()) allInterfacesImplementedBy_find(intf, set); } while ((c = c.getSuperclass()) != null); } static Method findMethod(Object o, String method, Object... args) { return findMethod_cached(o, method, args); } static boolean findMethod_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } static Method findStaticMethod(Class c, String method, Object... args) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (!m.getName().equals(method)) continue; if ((m.getModifiers() & Modifier.STATIC) == 0 || !findStaticMethod_checkArgs(m, args)) continue; return m; } c = c.getSuperclass(); } return null; } static boolean findStaticMethod_checkArgs(Method m, Object[] args) { Class[] types = m.getParameterTypes(); if (types.length != args.length) return false; for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) return false; return true; } static String unquote(String s) { if (s == null) return null; if (startsWith(s, '[')) { int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; if (i < s.length() && s.charAt(i) == '[') { String m = s.substring(1, i); if (s.endsWith("]" + m + "]")) return s.substring(i+1, s.length()-i-1); } } if (s.length() > 1) { char c = s.charAt(0); if (c == '\"' || c == '\'') { int l = endsWith(s, c) ? s.length()-1 : s.length(); StringBuilder sb = new StringBuilder(l-1); for (int i = 1; i < l; i++) { char ch = s.charAt(i); if (ch == '\\') { char nextChar = (i == l - 1) ? '\\' : s.charAt(i + 1); // Octal escape? if (nextChar >= '0' && nextChar <= '7') { String code = "" + nextChar; i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; } } sb.append((char) Integer.parseInt(code, 8)); continue; } switch (nextChar) { case '\"': ch = '\"'; break; case '\\': ch = '\\'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\'': ch = '\''; break; // Hex Unicode: u???? case 'u': if (i >= l - 5) { ch = 'u'; break; } int code = Integer.parseInt( "" + s.charAt(i + 2) + s.charAt(i + 3) + s.charAt(i + 4) + s.charAt(i + 5), 16); sb.append(Character.toChars(code)); i += 5; continue; default: ch = nextChar; // added by Stefan } i++; } sb.append(ch); } return sb.toString(); } } return s; // not quoted - return original } static List quoteAll(Collection l) { List x = new ArrayList(); for (String s : l) x.add(quote(s)); return x; } static int _hashCode(Object a) { return a == null ? 0 : a.hashCode(); } static ArrayList toList(A[] a) { return asList(a); } static ArrayList toList(int[] a) { return asList(a); } static ArrayList toList(Set s) { return asList(s); } static ArrayList toList(Iterable s) { return asList(s); } static boolean arraysEqual(Object[] a, Object[] b) { if (a.length != b.length) return false; for (int i = 0; i < a.length; i++) if (neq(a[i], b[i])) return false; return true; } static UnsupportedOperationException unsupportedOperation() { throw new UnsupportedOperationException(); } static String shortClassName_dropNumberPrefix(Object o) { return dropNumberPrefix(shortClassName(o)); } static int boostHashCombine(int a, int b) { return a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2)); } // MetaTransformer that understands Transformable and List static MetaTransformer defaultMetaTransformer() { return metaTransformer_transformableAndList(); } static String quote(Object o) { if (o == null) return "null"; return quote(str(o)); } static String quote(String s) { if (s == null) return "null"; StringBuilder out = new StringBuilder((int) (l(s)*1.5+2)); quote_impl(s, out); return out.toString(); } static void quote_impl(String s, StringBuilder out) { out.append('"'); int l = s.length(); for (int i = 0; i < l; i++) { char c = s.charAt(i); if (c == '\\' || c == '"') out.append('\\').append(c); else if (c == '\r') out.append("\\r"); else if (c == '\n') out.append("\\n"); else if (c == '\t') out.append("\\t"); else if (c == '\0') out.append("\\0"); else out.append(c); } out.append('"'); } static void replaceTokens(List tok, int i, int j, String s) { clearAllTokens(tok, i+1, j); tok.set(i, s); } static void replaceTokens(List tok, String s) { clearAllTokens(tok, 1, l(tok)); tok.set(0, s); } static Map putAll(Map a, Map b) { if (a != null && b != null) a.putAll(b); return a; } static MultiMap putAll(MultiMap a, Map b) { if (a != null) a.putAll((Map) b); return a; } static Map putAll(Map a, Object... b) { if (a != null) litmap_impl(a, b); return a; } static void remove(List l, int i) { if (l != null && i >= 0 && i < l(l)) l.remove(i); } static void remove(Collection l, A a) { if (l != null) l.remove(a); } static B remove(Map map, Object a) { return map == null ? null : map.remove(a); } static void remove(BitSet bs, int i) { bs.clear(i); } static A getAndClear(IVar v) { A a = v.get(); v.set(null); return a; } static Set keySet(Map map) { return map == null ? new HashSet() : map.keySet(); } static Set keySet(Object map) { return keys((Map) map); } static Set keySet(MultiMap mm) { return mm.keySet(); } static int keysSize(MultiMap mm) { return lKeys(mm); } static A reverseGet(List l, int idx) { if (l == null || idx < 0) return null; int n = l(l); return idx < n ? l.get(n-1-idx) : null; } static Map cloneMap(Map map) { if (map == null) return new HashMap(); // assume mutex is equal to map synchronized(map) { return map instanceof TreeMap ? new TreeMap((TreeMap) map) // copies comparator : map instanceof LinkedHashMap ? new LinkedHashMap(map) : new HashMap(map); } } static List cloneMap(Iterable l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : cloneList(l)) x.add(f.get(o)); return x; } static Collection values(Map map) { return map == null ? emptyList() : map.values(); } // convenience shortcut for values_gen static Collection values(Object map) { return values((Map) map); } static Collection values(MultiMap mm) { return mm == null ? emptyList() : concatLists(values(mm.data)); } static BigInteger plus(BigInteger a, BigInteger b) { return a.add(b); } static BigInteger plus(BigInteger a, long b) { return a.add(bigint(b)); } static Method hashMap_findKey_method; static A hashMap_findKey(HashMap map, Object key) { try { if (hashMap_findKey_method == null) hashMap_findKey_method = findMethodNamed(HashMap.class, "getNode"); Map.Entry entry = (Map.Entry) hashMap_findKey_method.invoke(map, hashMap_internalHash(key), key); // java.util.Map.Entry entry = (java.util.Map.Entry) call(hash, 'getNode, hashMap_internalHash(key), wkey); return entry == null ? null : entry.getKey(); } catch (Exception __e) { throw rethrow(__e); } } static String commaCombine(Object... l) { return joinNemptiesWithComma(flattenCollectionsAndArrays(ll(l))); } static int hashCodeFor(Object a) { return a == null ? 0 : a.hashCode(); } static Boolean not(Boolean b) { return b == null ? null : !b; } static A set(A o, String field, Object value) { if (o == null) return null; if (o instanceof Class) set((Class) o, field, value); else try { Field f = set_findField(o.getClass(), field); makeAccessible(f); smartSet(f, o, value); } catch (Exception e) { throw new RuntimeException(e); } return o; } static void set(Class c, String field, Object value) { if (c == null) return; try { Field f = set_findStaticField(c, field); makeAccessible(f); smartSet(f, null, value); } catch (Exception e) { throw new RuntimeException(e); } } static Field set_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); } static Field set_findField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field)) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); } static void set(BitSet bs, int idx) { { if (bs != null) bs.set(idx); } } static Method findMethod_cached(Object o, String method, Object... args) { try { if (o == null) return null; if (o instanceof Class) { _MethodCache cache = callOpt_getCache((Class) o); List methods = cache.cache.get(method); if (methods != null) for (Method m : methods) if (isStaticMethod(m) && findMethod_checkArgs(m, args, false)) return m; return null; } else { _MethodCache cache = callOpt_getCache(o.getClass()); List methods = cache.cache.get(method); if (methods != null) for (Method m : methods) if (findMethod_checkArgs(m, args, false)) return m; return null; } } catch (Exception __e) { throw rethrow(__e); } } static boolean endsWith(String a, String b) { return a != null && a.endsWith(b); } static boolean endsWith(String a, char c) { return nempty(a) && lastChar(a) == c; } static boolean endsWith(String a, String b, Matches m) { if (!endsWith(a, b)) return false; m.m = new String[] {dropLast(l(b), a)}; return true; } static String dropNumberPrefix(String s) { return dropFirst(s, indexOfNonDigit(s)); } static String shortClassName(Object o) { if (o == null) return null; Class c = o instanceof Class ? (Class) o : o.getClass(); String name = c.getName(); return shortenClassName(name); } // MetaTransformer that understands Transformable and List static MetaTransformer metaTransformer_transformableAndList() { return new MetaTransformer(new MetaTransformer.StructureHandler() { public Object transform(Object o, IF1 recurse) { if (o instanceof Transformable) return ((Transformable) o).transformUsing(recurse); if (o instanceof List) return map_ping(recurse, ((List) o)); return null; } public void visit(Object o, IVF1 recurse) { if (o instanceof Visitable) ((Visitable) o).visitUsing(recurse); else if (o instanceof List) for (Object x : ((List) o)) { ping(); recurse.get(x); } } }); } static void clearAllTokens(List tok) { for (int i = 0; i < tok.size(); i++) tok.set(i, ""); } static void clearAllTokens(List tok, int i, int j) { for (; i < j; i++) tok.set(i, ""); } static HashMap litmap(Object... x) { HashMap map = new HashMap(); litmap_impl(map, x); return map; } static void litmap_impl(Map map, Object... x) { if (x != null) for (int i = 0; i < x.length-1; i += 2) if (x[i+1] != null) map.put(x[i], x[i+1]); } static int lKeys(MultiMap mm) { return mm == null ? 0 : mm.keysSize(); } static BigInteger bigint(String s) { return new BigInteger(s); } static BigInteger bigint(long l) { return BigInteger.valueOf(l); } // This is a bit rough... finds static and non-static methods. static Method findMethodNamed(Object obj, String method) { if (obj == null) return null; if (obj instanceof Class) return findMethodNamed((Class) obj, method); return findMethodNamed(obj.getClass(), method); } static Method findMethodNamed(Class c, String method) { while (c != null) { for (Method m : c.getDeclaredMethods()) if (m.getName().equals(method)) { makeAccessible(m); return m; } c = c.getSuperclass(); } return null; } static int hashMap_internalHash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } static String joinNemptiesWithComma(Object... strings) { return joinNempties(", ", strings); } static String joinNemptiesWithComma(Iterable strings) { return joinNempties(", ", strings); } static List flattenCollectionsAndArrays(Iterable a) { List l = new ArrayList(); for (Object x : a) if (x instanceof Collection) l.addAll(flattenCollectionsAndArrays((Collection) x)); else if (x instanceof Object[]) l.addAll(flattenCollectionsAndArrays(asList((Object[]) x))); else l.add(x); return l; } static void smartSet(Field f, Object o, Object value) throws Exception { try { f.set(o, value); } catch (Exception e) { Class type = f.getType(); // take care of common case (long to int) if (type == int.class && value instanceof Long) { f.set(o, ((Long) value).intValue()); return; } if (type == boolean.class && value instanceof String) { f.set(o, isTrueOrYes(((String) value))); return; } if (type == LinkedHashMap.class && value instanceof Map) { f.set(o, asLinkedHashMap((Map) value)); return; } throw e; } } static char lastChar(String s) { return empty(s) ? '\0' : s.charAt(l(s)-1); } static A[] dropLast(A[] a) { return dropLast(a, 1); } static A[] dropLast(A[] a, int n) { if (a == null) return null; n = Math.min(n, a.length); A[] b = arrayOfSameType(a, a.length-n); System.arraycopy(a, 0, b, 0, b.length); return b; } static List dropLast(List l) { return subList(l, 0, l(l)-1); } static List dropLast(int n, List l) { return subList(l, 0, l(l)-n); } static List dropLast(Iterable l) { return dropLast(asList(l)); } static String dropLast(String s) { return substring(s, 0, l(s)-1); } static String dropLast(String s, int n) { return substring(s, 0, l(s)-n); } static String dropLast(int n, String s) { return dropLast(s, n); } static String[] dropFirst(int n, String[] a) { return drop(n, a); } static String[] dropFirst(String[] a) { return drop(1, a); } static Object[] dropFirst(Object[] a) { return drop(1, a); } static List dropFirst(List l) { return dropFirst(1, l); } static List dropFirst(int n, Iterable i) { return dropFirst(n, toList(i)); } static List dropFirst(Iterable i) { return dropFirst(toList(i)); } static List dropFirst(int n, List l) { return n <= 0 ? l : new ArrayList(l.subList(Math.min(n, l.size()), l.size())); } static List dropFirst(List l, int n) { return dropFirst(n, l); } static String dropFirst(int n, String s) { return substring(s, n); } static String dropFirst(String s, int n) { return substring(s, n); } static String dropFirst(String s) { return substring(s, 1); } static int indexOfNonDigit(String s) { int n = l(s); for (int i = 0; i < n; i++) if (!isDigit(s.charAt(i))) return i; return -1; } static String shortenClassName(String name) { if (name == null) return null; int i = lastIndexOf(name, "$"); if (i < 0) i = lastIndexOf(name, "."); return i < 0 ? name : substring(name, i+1); } static List map_ping(Iterable l, Object f) { return map_ping(f, l); } static List map_ping(Object f, Iterable l) { List x = emptyList(l); if (l != null) for (Object o : l) x.add(callF(f, o)); return x; } static List map_ping(Iterable l, F1 f) { return map_ping(f, l); } static List map_ping(F1 f, Iterable l) { List x = emptyList(l); if (l != null) for (A o : l) x.add(callF(f, o)); return x; } static List map_ping(IF1 f, Iterable l) { return map_ping(l, f); } static List map_ping(Iterable l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(f.get(o)); } return x; } static List map_ping(IF1 f, A[] l) { return map_ping(l, f); } static List map_ping(A[] l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(f.get(o)); } return x; } static List map_ping(Object f, Object[] l) { return map_ping(f, asList(l)); } static List map_ping(Object[] l, Object f) { return map_ping(f, l); } static List map_ping(Object f, Map map) { return map_ping(map, f); } // map_ping: func(key, value) -> list element static List map_ping(Map map, Object f) { List x = new ArrayList(); if (map != null) for (Object _e : map.entrySet()) { ping(); Map.Entry e = (Map.Entry) _e; x.add(callF(f, e.getKey(), e.getValue())); } return x; } static List map_ping(Map map, IF2 f) { return map_ping(map, (Object) f); } static boolean isTrueOrYes(Object o) { return isTrueOpt(o) || o instanceof String && (eqicOneOf(((String) o), "1", "t", "true") || isYes(((String) o))); } static LinkedHashMap asLinkedHashMap(Map map) { if (map instanceof LinkedHashMap) return (LinkedHashMap) map; LinkedHashMap m = new LinkedHashMap(); if (map != null) synchronized(collectionMutex(map)) { m.putAll(map); } return m; } static A[] arrayOfSameType(A[] a, int n) { return newObjectArrayOfSameType(a, n); } static String[] drop(int n, String[] a) { n = Math.min(n, a.length); String[] b = new String[a.length-n]; System.arraycopy(a, n, b, 0, b.length); return b; } static Object[] drop(int n, Object[] a) { n = Math.min(n, a.length); Object[] b = new Object[a.length-n]; System.arraycopy(a, n, b, 0, b.length); return b; } static boolean isDigit(char c) { return Character.isDigit(c); } static int lastIndexOf(String a, String b) { return a == null || b == null ? -1 : a.lastIndexOf(b); } static int lastIndexOf(String a, char b) { return a == null ? -1 : a.lastIndexOf(b); } // starts searching from i-1 static int lastIndexOf(List l, int i, A a) { if (l == null) return -1; for (i = min(l(l), i)-1; i >= 0; i--) if (eq(l.get(i), a)) return i; return -1; } static int lastIndexOf(List l, A a) { if (l == null) return -1; for (int i = l(l)-1; i >= 0; i--) if (eq(l.get(i), a)) return i; return -1; } static boolean isTrueOpt(Object o) { if (o instanceof Boolean) return ((Boolean) o).booleanValue(); return false; } static boolean isTrueOpt(String field, Object o) { return isTrueOpt(getOpt(field, o)); } static boolean eqicOneOf(String s, String... l) { for (String x : l) if (eqic(s, x)) return true; return false; } static List isYes_yesses = litlist("y", "yes", "yeah", "y", "yup", "yo", "corect", "sure", "ok", "afirmative"); // << collapsed words, so "corect" means "correct" static boolean isYes(String s) { return isYes_yesses.contains(collapseWord(toLowerCase(firstWord2(s)))); } static A[] newObjectArrayOfSameType(A[] a) { return newObjectArrayOfSameType(a, a.length); } static A[] newObjectArrayOfSameType(A[] a, int n) { return (A[]) Array.newInstance(a.getClass().getComponentType(), n); } static ArrayList litlist(A... a) { ArrayList l = new ArrayList(a.length); for (A x : a) l.add(x); return l; } static String collapseWord(String s) { if (s == null) return ""; StringBuilder buf = new StringBuilder(); for (int i = 0; i < l(s); i++) if (i == 0 || !charactersEqualIC(s.charAt(i), s.charAt(i-1))) buf.append(s.charAt(i)); return buf.toString(); } static List toLowerCase(List strings) { List x = new ArrayList(); for (String s : strings) x.add(s.toLowerCase()); return x; } static String[] toLowerCase(String[] strings) { String[] x = new String[l(strings)]; for (int i = 0; i < l(strings); i++) x[i] = strings[i].toLowerCase(); return x; } static String toLowerCase(String s) { return s == null ? "" : s.toLowerCase(); } static String firstWord2(String s) { s = xltrim(s); if (empty(s)) return ""; if (isLetterOrDigit(first(s))) return takeCharsWhile(__36 -> isLetterOrDigit(__36), s); else return "" + first(s); } static boolean charactersEqualIC(char c1, char c2) { if (c1 == c2) return true; char u1 = Character.toUpperCase(c1); char u2 = Character.toUpperCase(c2); if (u1 == u2) return true; return Character.toLowerCase(u1) == Character.toLowerCase(u2); } static String xltrim(String s) { int i = 0, n = l(s); while (i < n && contains(" \t\r\n", s.charAt(i))) ++i; return substr(s, i); } static boolean isLetterOrDigit(char c) { return Character.isLetterOrDigit(c); } // pred: char -> bool static String takeCharsWhile(String s, Object pred) { int i = 0; while (i < l(s) && isTrue(callF(pred, s.charAt(i)))) ++i; return substring(s, 0, i); } static String takeCharsWhile(IF1 f, String s) { return takeCharsWhile(s, f); } static String substr(String s, int x) { return substring(s, x); } static String substr(String s, int x, int y) { return substring(s, x, y); } static class MetaTransformer { static interface StructureHandler { default Object transform(Object o, IF1 recurse) { return null; } void visit(Object o, IVF1 recurse); } List structureHandlers; //bool keepUnknown; // assume true for now Set seen; // initialize to identityHashSet() if you want to check for cycles MetaTransformer() {} MetaTransformer(StructureHandler... handlers) { structureHandlers = asList(handlers); } final void add(StructureHandler sh){ addStructureHandler(sh); } void addStructureHandler(StructureHandler sh) { structureHandlers.add(sh); } // if f returns null, go through structure // if f returns an object, do not recurse into it // TODO: honor seen Object transform(IF1 f, Object o) { ping(); Object x = f.get(o); if (x != null) return x; IF1 recurse = liftFunction(f); for (StructureHandler h : unnullForIteration(structureHandlers)) { ping(); { Object __2= h.transform(o, recurse); if (__2 != null) return __2; } } //ret keepUnknown ? o : null; return o; } // transform without result void visit(IVF1 f, Object o) { ping(); if (o == null) return; if (seen != null && !seen.add(o)) return; f.get(o); for (StructureHandler h : unnullForIteration(structureHandlers)) { ping(); IVF1 recurse = x -> { markPointer(o, x); visit(f, x); }; h.visit(o, recurse); } } void visit_vstack(IVF1 f, Object o) { vstackCompute(new visit_vstackComputable(f, o)); } class visit_vstackComputable extends VStackComputableWithStep implements IFieldsToList{ IVF1 f; Object o; visit_vstackComputable() {} visit_vstackComputable(IVF1 f, Object o) { this.o = o; this.f = f;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + f + ", " + o + ")"; } public boolean equals(Object _o) { if (!(_o instanceof visit_vstackComputable)) return false; visit_vstackComputable __0 = (visit_vstackComputable) _o; return eq(f, __0.f) && eq(o, __0.o); } public int hashCode() { int h = 1091269166; h = boostHashCombine(h, _hashCode(f)); h = boostHashCombine(h, _hashCode(o)); return h; } public Object[] _fieldsToList() { return new Object[] {f, o}; } void step(VStack stack) { if (step == 0) { ping(); if (o == null) { stack._return(); return; } step++; } if (step == 1) { if (seen != null && !seen.add(o)) { stack._return(); return; } ++step; } if (step == 2) { f.get(o); ++step; } stack.replace(new ForEach_vstack<>(structureHandlers, h -> { IVF1 recurse = x -> { markPointer(o, x); stack.call(new visit_vstackComputable(f, x)); }; h.visit(o, recurse); })); } } // lift transformer function to handle structures IF1 liftFunction(IF1 f) { return o -> transform(f, o); } // check if any element satisfies a predicate. // Note: might even be faster without the cancel point logic boolean any(IF1 pred, Object o) { Flag flag = new Flag(); withCancelPoint(cp -> visit(x -> { if (pred.get(x)) { flag.raise(); cancelTo(cp); } }, o) ); return flag.isUp(); } void addVisitor(IVF1 visitor) { if (visitor == null) return; addStructureHandler(new StructureHandler() { public void visit(Object o, IVF1 recurse) { visitor.get(o); } }); } void avoidCycles() { seen = identityHashSet(); } transient IVF2 markPointer; void markPointer(Object a, Object b) { if (markPointer != null) markPointer.get(a, b); else markPointer_base(a, b); } final void markPointer_fallback(IVF2 _f, Object a, Object b) { if (_f != null) _f.get(a, b); else markPointer_base(a, b); } void markPointer_base(Object a, Object b) {} } abstract static class VStackComputableWithStep implements VStack.Computable { int step; // you can implement either of these public void step(VStack stack, Object subComputationResult) { step(stack); } void step(VStack stack) {} } static class ForEach_vstack extends VStackComputableWithStep implements IFieldsToList{ Iterable l; IVF1 body; ForEach_vstack() {} ForEach_vstack(Iterable l, IVF1 body) { this.body = body; this.l = l;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + l + ", " + body + ")"; }public Object[] _fieldsToList() { return new Object[] {l, body}; } Iterator it; void step(VStack stack) { if (step == 0) { if (l == null) { stack._return(); return; } it = iterator(l); ++step; } if (!it.hasNext()) { stack._return(); return; } body.get(it.next()); } } static class VStack implements Steppable { List stack = new ArrayList(); Object latestResult; transient Object newResult; // the null sentinel replaces a null function result // when stored in latestResult static class NullSentinel {} static NullSentinel nullSentinel = new NullSentinel(); VStack() {} VStack(Computable computation) { push(computation); } VStack(Iterable l) { pushAll(l); } // A is what the function returns interface Computable { public void step(VStack stack, Object subComputationResult); } private Object deSentinel(Object o) { return o instanceof NullSentinel ? null : o; } private Object sentinel(Object o) { return o == null ? nullSentinel : o; } // called by computations or users to start a subroutine final void call(Computable computation){ push(computation); } void push(Computable computation) { stack.add(computation); } // perform a computation step. returns false iff done public boolean step() { if (empty(stack)) return false; newResult = null; last(stack).step(this, result()); latestResult = newResult; newResult = null; return true; } // called from a computation to return a value void _return() { _return(null); } void _return(Object value) { newResult = sentinel(value); removeLast(stack); } // called from a computation to tail-call another routine final void replace(Computable computation){ tailCall(computation); } void tailCall(Computable computation) { removeLast(stack); stack.add(computation); } // all-in-one evaluation function - call on an empty stack A compute(Computable computation) { if (computation == null) return null; push(computation); stepAll(this); return (A) latestResult; } // return result of just completed computation or sub-computation final Object subResult(){ return result(); } Object result() { return deSentinel(latestResult); } boolean hasSubResult() { return latestResult != null; } void pushAll(Iterable l) { for (Computable c : unnullForIteration(l)) push(c); } void add(Runnable r) { if (r == null) return; push((stack, subComputationResult) -> r.run()); } } static interface IVF2 { void get(A a, B b); } /** this class is fully thread-safe */ static class Flag implements Runnable { private boolean up = false; /** returns true if flag was down before (i.e. flag was actually raised right now) */ public synchronized boolean raise() { if (!up) { up = true; notifyAll(); return true; } else return false; } public synchronized void waitUntilUp() { while (!up) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } public boolean waitUntilUp(double timeout) { return waitUntilUp(toMS(timeout)); } public synchronized boolean waitUntilUp(long timeout) { if (!up) { try { wait(timeout); } catch (InterruptedException e) { e.printStackTrace(); } } return isUp(); } public synchronized boolean isUp() { return up; } boolean get() { return isUp(); } public String toString() { return isUp() ? "up" : "down"; } // currently does a semi-active wait with latency = 50 ms public void waitForThisOr(Flag otherFlag) { try { while (!isUp() && !otherFlag.isUp()) Thread.sleep(50); } catch (Exception __e) { throw rethrow(__e); } } public void run() { raise(); } } static interface Steppable { public boolean step(); // return false if done } static A vstackCompute(VStack.Computable computation) { return vStackCompute(computation); } static void withCancelPoint(VF1 r) { CancelPoint cp = newCancelPoint(); try { try { callF(r, cp); } catch (Throwable e) { e = innerException(e); if (!(e instanceof CancelToCancelPoint && ((CancelToCancelPoint) e).cp == cp)) rethrow(e); } } finally { _close(cp); }} static void withCancelPoint(IVF1 r) { CancelPoint cp = newCancelPoint(); try { try { r.get(cp); } catch (Throwable e) { e = innerException(e); if (!(e instanceof CancelToCancelPoint && ((CancelToCancelPoint) e).cp == cp)) rethrow(e); } } finally { _close(cp); }} static RuntimeException cancelTo(CancelPoint cp) { if (cp.closed) throw fail("cancel point closed"); throw new CancelToCancelPoint(cp); } static boolean step(Steppable steppable) { return steppable == null ? null : steppable.step(); } static A last(List l) { return empty(l) ? null : l.get(l.size()-1); } static char last(String s) { return empty(s) ? '#' : s.charAt(l(s)-1); } static int last(int[] a) { return l(a) != 0 ? a[l(a)-1] : 0; } static double last(double[] a) { return l(a) != 0 ? a[l(a)-1] : 0; } static A last(A[] a) { return l(a) != 0 ? a[l(a)-1] : null; } static A last(Iterator it) { A a = null; while (it.hasNext()) { ping(); a = it.next(); } return a; } static A last(Collection l) { if (l == null) return null; if (l instanceof List) return (A) last((List) l); if (l instanceof SortedSet) return (A) last((SortedSet) l); Iterator it = iterator(l); A a = null; while (it.hasNext()) { ping(); a = it.next(); } return a; } static A last(SortedSet l) { return l == null ? null : l.last(); } static void removeLast(List l) { if (!l.isEmpty()) l.remove(l(l)-1); } static void removeLast(List l, int n) { removeSubList(l, l(l)-n); } static void removeLast(int n, List l) { removeLast(l, n); } static void stepAll(Steppable s) { if (s != null) while (s.step()) { ping(); } } // based on: https://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html // TODO: implement NavigableSet // RAM use in a CompressedOOPS JVM (bytes per element): // ~12 when elements are inserted in sorted order // ~13.7 when elements are inserted in random order // // (Obviously more for very small sets.) static class HyperCompactTreeSet extends AbstractSet { // A symbol table implemented using a left-leaning red-black BST. // This is the 2-3 version. // Note: We sometimes cast the nullSentinel to A // which is technically incorrect but ok because of type erasure. // May want to fix just to be clean on the source level too. private static final boolean RED = true; private static final boolean BLACK = false; // replacement for null elements private static final Object nullSentinel = new Object(); private Node root; // root of the BST int size; // size of tree set // BST helper node data type abstract static class Node { A val; // associated data Node left() { return null; } // get left subtree abstract Node setLeft(Node left); // set left subtree - return potentially replaced node Node right() { return null; } // get right subtree abstract Node setRight(Node right); // set right subtree - return potentially replaced node abstract boolean color(); abstract Node convertToBlack(); abstract Node convertToRed(); abstract Node invertColor(); Node convertToColor(boolean color) { return color == RED ? convertToRed() : convertToBlack(); } abstract boolean isLeaf(); } // This represents a common case near a red leaf - a black node // containing a red leaf in the left slot and null in the right slot. // Combined with the direct storage of black leaf children in NonLeaf, // this is all we need to get rid of all the leaf overhead. Yay! static class SpecialNode extends Node { A leftVal; SpecialNode(A leftVal, A val) { this.val = val; this.leftVal = leftVal;} boolean color() { return BLACK; } Node convertToBlack() { return this; } Node convertToRed() { return newNode(RED, val, left(), right()); } Node invertColor() { return convertToRed(); } Node left() { return newLeaf(RED, leftVal); } Node setLeft(Node left) { // Can we keep the optimized representation? (Probably this // is never going to be true.) if (left != null && left.isLeaf() && left.color() == RED) { leftVal = left.val; return this; } else return newNode(BLACK, val, left, right()); } Node right() { return null; } Node setRight(Node right) { if (right == null) return this; return newNode(color(), val, left(), right); } boolean isLeaf() { return false; } } abstract static class NonLeaf extends Node { // either a Node or a (sentinelled) direct user value Object left, right; // color of leaf if left is a user value boolean defaultLeftLeafColor() { return BLACK; } // color of leaf if right is a user value boolean defaultRightLeafColor() { return BLACK; } Node left() { return left == null ? null : left instanceof Node ? (Node) left : newLeaf(defaultLeftLeafColor(), (A) left); } void setLeft_noMorph(Node left) { this.left = left != null && left.isLeaf() && left.color() == defaultLeftLeafColor() ? left.val : left; } void setRight_noMorph(Node right) { this.right = right != null && right.isLeaf() && right.color() == defaultRightLeafColor() ? right.val : right; } Node setLeft(Node left) { if (color() == BLACK && right == null && left != null && left.isLeaf() && left.color() == RED) return new SpecialNode(left.val, val); setLeft_noMorph(left); if (left == null && right() == null) return newLeaf(color(), val); return this; } Node right() { return right == null ? null : right instanceof Node ? (Node) right : newLeaf(defaultRightLeafColor(), (A) right); } Node setRight(Node right) { // Setting right to null may produce either a leaf or a // special node, so we just go through newNode. if (right == null && this.right != null) return newNode(color(), val, left(), null); // New right is not null, so we compress (if possible) and store it setRight_noMorph(right); return this; } boolean isLeaf() { return false; } } static class BlackNode extends NonLeaf { BlackNode(A val) { this.val = val;} boolean color() { return BLACK; } Node convertToBlack() { return this; } Node convertToRed() { return newNode(RED, val, left(), right()); } Node invertColor() { return convertToRed(); } } static class RedNode extends NonLeaf { RedNode(A val) { this.val = val;} boolean color() { return RED; } Node convertToBlack() { return newNode(BLACK, val, left(), right()); } Node convertToRed() { return this; } Node invertColor() { return convertToBlack(); } } abstract static class Leaf extends Node { boolean isLeaf() { return true; } Node setLeft(Node left) { return left == null ? this : newNode(color(), val, left, null); } Node setRight(Node right) { return right == null ? this : newNode(color(), val, null, right); } } static class BlackLeaf extends Leaf { BlackLeaf(A val) { this.val = val;} boolean color() { return BLACK; } Node convertToBlack() { return this; } Node convertToRed() { return new RedLeaf(val); } Node invertColor() { return convertToRed(); } } static class RedLeaf extends Leaf { RedLeaf(A val) { this.val = val;} boolean color() { return RED; } Node convertToBlack() { return new BlackLeaf(val); } Node convertToRed() { return this; } Node invertColor() { return convertToBlack(); } } HyperCompactTreeSet() {} HyperCompactTreeSet(Collection cl) { addAll(cl); } private static Object deSentinel(Object o) { return o == nullSentinel ? null : o; } private static Object sentinel(Object o) { return o == null ? nullSentinel : o; } // returns false on null (algorithm needs this) static boolean isRed(Node x) { return x != null && x.color() == RED; } static Node newLeaf(boolean color, A val) { return color == RED ? new RedLeaf(val) : new BlackLeaf(val); } static Node newNode(boolean color, A val, Node left, Node right) { // Make leaf (always a temporary object now) if (left == null && right == null) return newLeaf(color, val); // Make special node if (color == BLACK && right == null && left != null && left.isLeaf() && left.color() == RED) return new SpecialNode(left.val, val); // Make normal non-leaf NonLeaf node = color == RED ? new RedNode(val) : new BlackNode(val); node.setLeft_noMorph(left); node.setRight_noMorph(right); return node; } public int size() { return size; } public boolean isEmpty() { return root == null; } public boolean add(A val) { val = (A) sentinel(val); int oldSize = size; root = put(root, val); root = root.convertToBlack(); return size > oldSize; } // insert the value in the subtree rooted at h private Node put(Node h, A val) { if (h == null) { ++size; return new RedLeaf(val); } int cmp = compare_deSentinel(val, h.val); if (cmp < 0) h = h.setLeft(put(h.left(), val)); else if (cmp > 0) h = h.setRight(put(h.right(), val)) ; else { /*h.val = val;*/ } // no overwriting // fix-up any right-leaning links if (isRed(h.right()) && !isRed(h.left())) h = rotateLeft(h); if (isRed(h.left()) && isRed(h.left().left())) h = rotateRight(h); if (isRed(h.left()) && isRed(h.right())) h = flipColors(h); return h; } final int compare_deSentinel(A a, A b) { return compare((A) deSentinel(a), (A) deSentinel(b)); } // override me if you wish int compare(A a, A b) { return cmp(a, b); } public boolean remove(Object key) { if (!contains(key)) return false; key = sentinel(key); // if both children of root are black, set root to red if (!isRed(root.left()) && !isRed(root.right())) root = root.convertToRed(); root = delete(root, (A) key); if (!isEmpty()) root = root.convertToBlack(); // assert check(); return true; } // delete the key-value pair with the given key rooted at h private Node delete(Node h, A key) { // assert get(h, key) != null; if (compare_deSentinel(key, h.val) < 0) { if (!isRed(h.left()) && !isRed(h.left().left())) h = moveRedLeft(h); h = h.setLeft(delete(h.left(), key)); } else { if (isRed(h.left())) h = rotateRight(h); if (compare_deSentinel(key, h.val) == 0 && (h.right() == null)) { --size; return null; } if (!isRed(h.right()) && !isRed(h.right().left())) h = moveRedRight(h); if (compare_deSentinel(key, h.val) == 0) { --size; Node x = min(h.right()); h.val = x.val; // h.val = get(h.right(), min(h.right()).val); // h.val = min(h.right()).val; h = h.setRight(deleteMin(h.right())); } else h = h.setRight(delete(h.right(), key)); } return balance(h); } // make a left-leaning link lean to the right private Node rotateRight(Node h) { // assert (h != null) && isRed(h.left()); Node x = h.left(); h = h.setLeft(x.right()); x = x.setRight(h); x = x.convertToColor(x.right().color()); x = x.setRight(x.right().convertToRed()); return x; } // make a right-leaning link lean to the left private Node rotateLeft(Node h) { // assert (h != null) && isRed(h.right()); Node x = h.right(); h = h.setRight(x.left()); x = x.setLeft(h); x = x.convertToColor(x.left().color()); x = x.setLeft(x.left().convertToRed()); return x; } // flip the colors of a node and its two children private Node flipColors(Node h) { // h must have opposite color of its two children // assert (h != null) && (h.left() != null) && (h.right() != null); // assert (!isRed(h) && isRed(h.left()) && isRed(h.right())) // || (isRed(h) && !isRed(h.left()) && !isRed(h.right())); h = h.setLeft(h.left().invertColor()); h = h.setRight(h.right().invertColor()); return h.invertColor(); } // Assuming that h is red and both h.left() and h.left().left() // are black, make h.left() or one of its children red. private Node moveRedLeft(Node h) { // assert (h != null); // assert isRed(h) && !isRed(h.left()) && !isRed(h.left().left()); h = flipColors(h); if (isRed(h.right().left())) { h = h.setRight(rotateRight(h.right())); h = rotateLeft(h); h = flipColors(h); } return h; } // Assuming that h is red and both h.right() and h.right().left() // are black, make h.right() or one of its children red. private Node moveRedRight(Node h) { // assert (h != null); // assert isRed(h) && !isRed(h.right()) && !isRed(h.right().left()); h = flipColors(h); if (isRed(h.left().left())) { h = rotateRight(h); h = flipColors(h); } return h; } // restore red-black tree invariant private Node balance(Node h) { // assert (h != null); if (isRed(h.right())) h = rotateLeft(h); if (isRed(h.left()) && isRed(h.left().left())) h = rotateRight(h); if (isRed(h.left()) && isRed(h.right())) h = flipColors(h); return h; } /** * Returns the height of the BST (for debugging). * @return the height of the BST (a 1-node tree has height 0) */ public int height() { return height(root); } private int height(Node x) { if (x == null) return -1; return 1 + Math.max(height(x.left()), height(x.right())); } public boolean contains(Object val) { return find(root, (A) sentinel(val)) != null; } public A find(A probeVal) { probeVal = (A) sentinel(probeVal); Node n = find(root, probeVal); return n == null ? null : n.val; } // value associated with the given key in subtree rooted at x; null if no such key private A get(Node x, A key) { x = find(x, key); return x == null ? null : x.val; } Node find(Node x, A key) { while (x != null) { int cmp = compare_deSentinel(key, x.val); if (cmp < 0) x = x.left(); else if (cmp > 0) x = x.right(); else return x; } return null; } private boolean check() { if (!is23()) println("Not a 2-3 tree"); if (!isBalanced()) println("Not balanced"); return is23() && isBalanced(); } // Does the tree have no red right links, and at most one (left) // red links in a row on any path? private boolean is23() { return is23(root); } private boolean is23(Node x) { if (x == null) return true; if (isRed(x.right())) return false; if (x != root && isRed(x) && isRed(x.left())) return false; return is23(x.left()) && is23(x.right()); } // do all paths from root to leaf have same number of black edges? private boolean isBalanced() { int black = 0; // number of black links on path from root to min Node x = root; while (x != null) { if (!isRed(x)) black++; x = x.left(); } return isBalanced(root, black); } // does every path from the root to a leaf have the given number of black links? private boolean isBalanced(Node x, int black) { if (x == null) return black == 0; if (!isRed(x)) black--; return isBalanced(x.left(), black) && isBalanced(x.right(), black); } public void clear() { root = null; size = 0; } // the smallest key in subtree rooted at x; null if no such key private Node min(Node x) { // assert x != null; while (x.left() != null) x = x.left(); return x; } private Node deleteMin(Node h) { if (h.left() == null) return null; if (!isRed(h.left()) && !isRed(h.left().left())) h = moveRedLeft(h); h = h.setLeft(deleteMin(h.left())); return balance(h); } public Iterator iterator() { return new MyIterator(); } class MyIterator extends IterableIterator { List> path = new ArrayList(); MyIterator() { fetch(root); } void fetch(Node node) { while (node != null) { path.add(node); node = node.left(); } } public boolean hasNext() { return !path.isEmpty(); } public A next() { if (path.isEmpty()) throw fail("no more elements"); Node node = popLast(path); // last node is always a leaf, so left is null // so proceed to fetch right branch fetch(node.right()); return (A) deSentinel(node.val); } } // Returns the smallest key in the symbol table greater than or equal to {@code key}. public A ceiling(A key) { key = (A) sentinel(key); Node x = ceiling(root, key); return x == null ? null : x.val; } // the smallest key in the subtree rooted at x greater than or equal to the given key Node ceiling(Node x, A key) { if (x == null) return null; int cmp = compare_deSentinel(key, x.val); if (cmp == 0) return x; if (cmp > 0) return ceiling(x.right(), key); Node t = ceiling(x.left(), key); if (t != null) return t; else return x; } public A floor(A key) { key = (A) sentinel(key); Node x = floor(root, key); return x == null ? null : x.val; } // the largest key in the subtree rooted at x less than or equal to the given key Node floor(Node x, A key) { if (x == null) return null; int cmp = compare_deSentinel(key, x.val); if (cmp == 0) return x; if (cmp < 0) return floor(x.left(), key); Node t = floor(x.right(), key); if (t != null) return t; else return x; } void testInternalStructure() { // one leaf object (root) is allowed - could even optimize that assertTrue(countLeafObjects() <= 1); } // count leaf objects we didn't optimize away int countLeafObjects() { return countLeafObjects(root); } int countLeafObjects(Node node) { if (node instanceof Leaf) return 1; if (node instanceof NonLeaf) return countLeafObjects(optCast(Node.class, ((NonLeaf) node).left)) + countLeafObjects(optCast(Node.class, ((NonLeaf) node).right)); return 0; } Collection unoptimizedNodes() { List out = new ArrayList(); findUnoptimizedNodes(out); return out; } void findUnoptimizedNodes(List out) { findUnoptimizedNodes(root, out); } void findUnoptimizedNodes(Node node, List out) { if (node == null) return; if (node instanceof NonLeaf) { if (isUnoptimizedNode((NonLeaf) node)) out.add((NonLeaf) node); findUnoptimizedNodes(optCast(Node.class, ((NonLeaf) node).left), out); findUnoptimizedNodes(optCast(Node.class, ((NonLeaf) node).right), out); } } boolean isUnoptimizedNode(Node node) { if (node instanceof NonLeaf) return ((NonLeaf) node).left instanceof Leaf || ((NonLeaf) node).right instanceof Leaf; return false; } // Compact me (minimize space use). Returns a compacted copy. // This only has an effect when elements were inserted in non-sorted // or and/or elements were removed. HyperCompactTreeSet compact() { return new HyperCompactTreeSet(this); } } static long toMS(double seconds) { return (long) (seconds*1000); } static A vStackCompute(VStack.Computable computation) { if (computation == null) return null; VStack stack = new VStack(computation); stepAll(stack); return (A) stack.result(); } static CancelPoint newCancelPoint() { return new CancelPoint(); } static Throwable innerException(Throwable e) { return getInnerException(e); } static void _close(AutoCloseable c) { if (c != null) try { c.close(); } catch (Throwable e) { // Some classes stupidly throw an exception on double-closing if (c instanceof javax.imageio.stream.ImageOutputStream) return; else throw rethrow(e); } } static void removeSubList(List l, int from, int to) { if (l != null) subList(l, from, to).clear(); } static void removeSubList(List l, int from) { if (l != null) subList(l, from).clear(); } static boolean isEmpty(Collection c) { return c == null || c.isEmpty(); } static boolean isEmpty(CharSequence s) { return s == null || s.length() == 0; } static boolean isEmpty(Object[] a) { return a == null || a.length == 0; } static boolean isEmpty(byte[] a) { return a == null || a.length == 0; } static boolean isEmpty(Map map) { return map == null || map.isEmpty(); } static String find(String pattern, String text) { Matcher matcher = Pattern.compile(pattern).matcher(text); if (matcher.find()) return matcher.group(1); return null; } static A find(Collection c, Object... data) { for (A x : c) if (checkFields(x, data)) return x; return null; } static A println(A a) { return print(a); } static A popLast(List l) { return liftLast(l); } static List popLast(int n, List l) { return liftLast(n, l); } static double floor(double d) { return Math.floor(d); } static A optCast(Class c, Object o) { return isInstance(c, o) ? (A) o : null; } static Throwable getInnerException(Throwable e) { if (e == null) return null; while (e.getCause() != null) e = e.getCause(); return e; } static Throwable getInnerException(Runnable r) { return getInnerException(getException(r)); } static boolean checkFields(Object x, Object... data) { for (int i = 0; i < l(data); i += 2) if (neq(getOpt(x, (String) data[i]), data[i+1])) return false; return true; } static A liftLast(List l) { if (empty(l)) return null; int i = l(l)-1; A a = l.get(i); l.remove(i); return a; } static List liftLast(int n, List l) { int i = l(l)-n; List part = cloneSubList(l, i); removeSubList(l, i); return part; } static Throwable getException(Runnable r) { try { callF(r); return null; } catch (Throwable e) { return e; } } static List cloneSubList(List l, int startIndex, int endIndex) { return newSubList(l, startIndex, endIndex); } static List cloneSubList(List l, int startIndex) { return newSubList(l, startIndex); } static List newSubList(List l, int startIndex, int endIndex) { return cloneList(subList(l, startIndex, endIndex)); } static List newSubList(List l, int startIndex) { return cloneList(subList(l, startIndex)); } static class CancelPoint implements AutoCloseable { volatile boolean closed = false; public void close() { closed = true; } } static class CancelToCancelPoint extends QuickException { CancelPoint cp; CancelToCancelPoint(CancelPoint cp) { this.cp = cp;} } static class QuickException extends RuntimeException { public Throwable fillInStackTrace() { return this; } QuickException() {} QuickException(Throwable e) { super(e); } QuickException(String msg) { super(msg); } QuickException(String msg, Throwable e) { super(msg, e); } } }