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<String> tok; int maxTokens = 3; // "top dogs" are the longest non-overlapping parses List<ParsedWithTokens<SomeDate>> topDogs(String s) { return pwt_topDogs(pwt_filterByType(SomeDate.class, allParses(s))); } SomeDate parse(String s) { return getVar(first(topDogs(s))); } IterableIterator<ParsedWithTokens> allParses(String s) { // tokenize, initialize List<ParsedWithTokens<String>> initials = pwt_initial(tok = javaTok(s), maxTokens); List<ParsedWithTokens> out = new ArrayList(); // find numbers List<ParsedWithTokens<Integer>> numbers = pwt_transform(number(), initials); // find ordinals (1st, 2nd, ...) List<ParsedWithTokens<Integer>> ordinals = new ArrayList(); for (ParsedWithTokens<Integer> number : numbers) for (ParsedWithTokens<String> ord : parseToTheRight(fixedToken("st", "nd", "rd", "th"), number)) ordinals.add(pwt_combine(number, ord)); //print(+ordinals); // "in <n> days" for (ParsedWithTokens<Integer> number : numbers) for (ParsedWithTokens<String> in : parseToTheLeft(fixedToken("in"), number)) for (ParsedWithTokens<String> days : parseToTheRight(fixedToken("day", "days"), number)) out.add(pwt_combine(new TodayPlus(number.get()), in, days)); // "<n> days from now" for (ParsedWithTokens<Integer> number : numbers) for (ParsedWithTokens<String> daysFromNow : parseToTheRight(fixedToken("day from now", "days from now"), number)) out.add(pwt_combine(new TodayPlus(number.get()), number, daysFromNow)); List<ParsedWithTokens<Integer>> years = pwt_filter(__17 -> isYear(__17), numbers); out.addAll(years); List<ParsedWithTokens<Integer>> months = pwt_filter(__18 -> isMonthNr(__18), numbers); List<ParsedWithTokens<Integer>> dayOfMonths = pwt_filter(__19 -> isDayOfMonth(__19), numbers); List<ParsedWithTokens<Weekday>> weekdays = pwt_transform(weekday(), initials); out.addAll(weekdays); // month names List<ParsedWithTokens<Month>> 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<String> week : pwt_transform(fixedToken("week"), initials)) for (ParsedWithTokens<String> 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 <weekday>" for (ParsedWithTokens<Weekday> weekday : weekdays) for (ParsedWithTokens<String> next : parseToTheLeft(fixedToken("next"), weekday)) out.add(pwt_combine(new Weekday(weekday.get().weekday, new CurrentWeekPlus(1)), next, weekday)); for (ParsedWithTokens<Integer> year : years) for (ParsedWithTokens<String> slash : parseToTheRight(fixedToken("/"), year)) for (ParsedWithTokens<Integer> month : pwt_toTheRightOf(months, slash)) for (ParsedWithTokens<String> slash2 : parseToTheRight(fixedToken("/"), month)) for (ParsedWithTokens<Integer> day : pwt_toTheRightOf(dayOfMonths, slash2)) out.add(pwt_combine(new Day(day.get(), new Month(month.get(), new Year(year.get()))), year, day)); List<ParsedWithTokens<Hour>> hours = pwt_transform(__20 -> numberToHour(__20), numbers); List<ParsedWithTokens<Integer>> minutes = pwt_filter(__21 -> isMinute(__21), numbers); List<ParsedWithTokens<Integer>> seconds = minutes; List<ParsedWithTokens<String>> colons = pwt_filter(t -> eq(t, ":"), initials); // 15:12 etc. List<ParsedWithTokens<Minute>> hoursAndMinutes = pwt_combine(hours, colons, minutes, (h, __, m) -> new Minute(m, h)); out.addAll(hoursAndMinutes); List<ParsedWithTokens<Second>> hoursAndMinutesAndSeconds = pwt_combine(hoursAndMinutes, colons, seconds, (hm, __, second) -> new Second(second, hm)); out.addAll(hoursAndMinutesAndSeconds); List<ParsedWithTokens<String>> amPMs = pwt_transform(fixedToken("am", "pm"), initials); // 3 am, 5 pm etc. List<ParsedWithTokens<Hour>> 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<Hour> time : amPMTimes) for (ParsedWithTokens<String> and : parseToTheLeft(fixedToken("and"), time)) for (ParsedWithTokens<Hour> 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<String, Integer> 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<String, String> fixedToken(String... tokens) { return fixedToken(litciset(tokens)); } IF1<String, String> fixedToken(Set<String> set) { return t -> contains(set, t) ? t : null; } IF1<String, Weekday> weekday() { return s -> { int n = parseEnglishWeekday(s); return n == 0 ? null : new Weekday(n); }; } IF1<String, Month> monthName() { return s -> { int n = parseEnglishMonthName(s); return n == 0 ? null : new Month(n); }; } <A, B> List<ParsedWithTokens<B>> parseToTheLeft(IF1<A, B> f, ParsedWithTokens p) { return pwt_transform(f, pwt_precedingTokens(1, maxTokens, p.start())); } <A, B> List<ParsedWithTokens<B>> parseToTheRight(IF1<A, B> f, ParsedWithTokens p) { return pwt_transform(f, pwt_followingTokens(1, maxTokens, p.remaining())); } } static <A> List<ParsedWithTokens<A>> pwt_topDogs(Iterable<ParsedWithTokens<A>> l) { List<ParsedWithTokens<A>> topDogs = new ArrayList(); for (ParsedWithTokens<A> 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 <A> List<ParsedWithTokens<A>> pwt_filterByType(Class<A> type, Iterable<ParsedWithTokens> l) { return (List) filter(l, p -> isInstance(type, p.get())); } static <A> A getVar(IF0<A> v) { return v == null ? null : v.get(); } static <A> A getVar(Optional<A> v) { return v == null ? null : v.orElse(null); } static Object first(Object list) { return first((Iterable) list); } static <A> A first(List<A> list) { return empty(list) ? null : list.get(0); } static <A> A first(A[] bla) { return bla == null || bla.length == 0 ? null : bla[0]; } static <A, B> Pair<A, B> first(Map<A, B> map) { return mapEntryToPair(first(entrySet(map))); } static <A, B> Pair<A, B> first(MultiMap<A, B> 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> A first(IterableIterator<A> i) { return first((Iterator<A>) i); } static <A> A first(Iterator<A> i) { return i == null || !i.hasNext() ? null : i.next(); } static <A> A first(Iterable<A> i) { if (i == null) return null; Iterator<A> 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, B> A first(Pair<A, B> p) { return p == null ? null : p.a; } static Byte first(byte[] l) { return empty(l) ? null : l[0]; } static <A> A first(A[] l, IF1<A, Boolean> pred) { return firstThat(l, pred); } static <A> A first(Iterable<A> l, IF1<A, Boolean> pred) { return firstThat(l, pred); } static <A> A first(IF1<A, Boolean> pred, Iterable<A> l) { return firstThat(pred, l); } static List<ParsedWithTokens<String>> pwt_initial(int maxTokens, String s) { return pwt_initial(s, maxTokens); } static List<ParsedWithTokens<String>> pwt_initial(String s, int maxTokens) { return pwt_initial(javaTok(s), maxTokens); } // maxTokens = how many code tokens per range (max) static List<ParsedWithTokens<String>> pwt_initial(List<String> tok, int maxTokens) { return concatMap(lai_codeTokens(tok), lai -> pwt_followingTokens(1, maxTokens, lai)); } static List<ParsedWithTokens<String>> pwt_initial(int maxTokens, List<String> tok) { return pwt_initial(tok, maxTokens); } // TODO: extended multi-line strings static int javaTok_n, javaTok_elements; static boolean javaTok_opt = false; static List<String> javaTok(String s) { ++javaTok_n; ArrayList<String> 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<String> javaTok(List<String> tok) { return javaTokWithExisting(join(tok), tok); } static <A, B> List<ParsedWithTokens<B>> pwt_transform(IF1<A, B> f, Iterable<ParsedWithTokens<A>> l) { return map_nonNulls(p -> { B b = f.get(p.get()); return b == null ? null : p.withValue(b); }, l); } static <A> ParsedWithTokens<A> 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 <A> ParsedWithTokens<A> pwt_combine(ParsedWithTokens<A> p1, ParsedWithTokens p2) { return pwt_combine(p1.get(), p1, p2); } // entirely different meaning static <A, B, C> List<ParsedWithTokens<C>> pwt_combine(Iterable<ParsedWithTokens<A>> l1, Iterable<ParsedWithTokens<B>> l2, IF2<A, B, C> f) { List<ParsedWithTokens<C>> out = new ArrayList(); for (ParsedWithTokens<A> a : l1) for (ParsedWithTokens<B> b : pwt_toTheRightOf(l2, a)) out.add(pwt_combine(f.get(a.get(), b.get()), a, b)); return out; } static <A, B, C, D> List<ParsedWithTokens<D>> pwt_combine(Iterable<ParsedWithTokens<A>> l1, Iterable<ParsedWithTokens<B>> l2, Iterable<ParsedWithTokens<C>> l3, IF3<A, B, C, D> f) { List<ParsedWithTokens<D>> out = new ArrayList(); for (ParsedWithTokens<A> a : l1) for (ParsedWithTokens<B> b : pwt_toTheRightOf(l2, a)) for (ParsedWithTokens<C> c : pwt_toTheRightOf(l3, b)) out.add(pwt_combine(f.get(a.get(), b.get(), c.get()), a, c)); return out; } static <A> List<ParsedWithTokens<A>> pwt_filter(IF1<A, Boolean> f, Iterable<ParsedWithTokens<A>> 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 <A> IterableIterator<ParsedWithTokens<A>> pwt_toTheRightOf(Iterable<ParsedWithTokens<A>> 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 <A> IterableIterator<ParsedWithTokens<A>> pwt_toTheLeftOf(Iterable<ParsedWithTokens<A>> l, ParsedWithTokens b) { return filterI(iterator(l), p -> { //print("ttlo: " + p.iRemaining + " / " + b.iStart); return (p.iRemaining | 1) == (b.iStart | 1); }); } static <A> IterableIterator<A> itIt(Iterable<A> l) { if (l == null) return emptyItIt(); if (l instanceof IterableIterator) return ((IterableIterator) l); Iterator<A> it = l.iterator(); if (it instanceof IterableIterator) return ((IterableIterator) it); return new IterableIterator<A>() { 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<String> litciset(String... items) { TreeSet<String> set = caseInsensitiveSet(); for (String a : items) set.add(a); return set; } static TreeSet<Symbol> litciset(Symbol... items) { TreeSet<Symbol> 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<String, Integer> 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<ParsedWithTokens<String>> pwt_precedingTokens(int minTokens, int maxTokens, ListAndIndex<String> 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<ParsedWithTokens<String>> pwt_followingTokens(int minTokens, int maxTokens, ListAndIndex<String> 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 <A> Collection<A> unnullForIteration(Collection<A> l) { return l == null ? immutableEmptyList() : l; } static <A> List<A> unnullForIteration(List<A> 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 <A, B> Map<A, B> unnullForIteration(Map<A, B> l) { return l == null ? immutableEmptyMap() : l; } static <A> Iterable<A> unnullForIteration(Iterable<A> i) { return i == null ? immutableEmptyList() : i; } static <A> 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 <A, B> Pair<A, B> unnullForIteration(Pair<A, B> p) { return p != null ? p : new Pair(null, null); } static long unnullForIteration(Long l) { return l == null ? 0L : l; } static <A> void listPut(List<A> l, int i, A a, A emptyElement) { listSet(l, i, a, emptyElement); } static <A> void listPut(List<A> l, int i, A a) { listSet(l, i, a); } static <A> ParsedWithTokens<A> pwt_winner(ParsedWithTokens<A> a, ParsedWithTokens<A> b) { return a == null ? b : b == null ? a : a.length() >= b.length() ? a : b; } static <A> A _get(List<A> 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> A _get(A[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : null; } static <A> List<A> uniquify(Collection<A> l) { return uniquifyList(l); } static <A> List<A> nonNulls(Iterable<A> l) { return withoutNulls(l); } static <A> List<A> nonNulls(A[] l) { return withoutNulls(l); } static <A, B> Map<A, B> nonNulls(Map<A, B> map) { return withoutNulls(map); } static <A> List<A> filter(Iterable<A> c, Object pred) { if (pred instanceof F1) return filter(c, (F1<A, Boolean>) 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 <A, B extends A> List<B> filter(Iterable<B> c, F1<A, Boolean> pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static <A, B extends A> List<B> filter(F1<A, Boolean> pred, Iterable<B> c) { return filter(c, pred); } //ifclass IF1 static <A, B extends A> List<B> filter(Iterable<B> c, IF1<A, Boolean> pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static <A, B extends A> List<B> filter(B[] c, IF1<A, Boolean> pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static <A, B extends A> List<B> filter(IF1<A, Boolean> pred, Iterable<B> 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 <A, B> Pair<A, B> mapEntryToPair(Map.Entry<A, B> e) { return e == null ? null : pair(e.getKey(), e.getValue()); } static <A, B> Set<Map.Entry<A,B>> entrySet(Map<A, B> map) { return _entrySet(map); } static <A, B> Pair<A, B> pair(A a, B b) { return new Pair(a, b); } static <A> Pair<A, A> pair(A a) { return new Pair(a, a); } static <A> A firstThat(Iterable<A> l, IF1<A, Boolean> pred) { for (A a : unnullForIteration(l)) if (pred.get(a)) return a; return null; } static <A> A firstThat(A[] l, IF1<A, Boolean> pred) { for (A a : unnullForIteration(l)) if (pred.get(a)) return a; return null; } static <A> A firstThat(IF1<A, Boolean> pred, Iterable<A> l) { return firstThat(l, pred); } static <A> A firstThat(IF1<A, Boolean> 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 <A, B, C extends Iterable<B>> List<B> concatMap(Iterable<A> l, IF1<A, C> f) { return concatMap(l, (Object) f); } static <A, B, C extends Iterable<B>> List<B> concatMap(IF1<A, C> f, Iterable<A> l) { return concatMap(l, f); } static <A, B, C extends Iterable<B>> List<B> concatMap(IF1<A, C> f, A[] l) { return concatMap((Object) f, l); } static List<ListAndIndex<String>> lai_codeTokens(List<String> 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<String> javaTokWithExisting(String s, List<String> existing) { ++javaTok_n; int nExisting = javaTok_opt && existing != null ? existing.size() : 0; ArrayList<String> 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 <A> String join(String glue, Iterable<A> strings) { if (strings == null) return ""; if (strings instanceof Collection) { if (((Collection) strings).size() == 1) return str(first((Collection) strings)); } StringBuilder buf = new StringBuilder(); Iterator<A> 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 <A> String join(Iterable<A> strings) { return join("", strings); } static <A> String join(Iterable<A> 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 <A, B> List<B> map_nonNulls(Iterable<A> l, F1<A, B> f) { return mapNonNulls(l, f); } static <A, B> List<B> map_nonNulls(F1<A, B> f, Iterable<A> l) { return mapNonNulls(f, l); } static <A, B> List<B> map_nonNulls(A[] l, IF1<A, B> f) { return mapNonNulls(l, f); } static <A, B> List<B> map_nonNulls(Iterable<A> l, IF1<A, B> f) { return mapNonNulls(l, f); } static <A, B> List<B> map_nonNulls(IF1<A, B> f, Iterable<A> 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<Integer> 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 extends Comparable<A>> 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> A get(List<A> l, int idx) { return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null; } // seems to conflict with other signatures /*static <A, B> B get(Map<A, B> map, A key) { ret map != null ? map.get(key) : null; }*/ static <A> 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<String> englishWeekdays_list = ll("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); static List<String> 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 <A> IterableIterator<A> filterI(Iterator<A> it, F1<A, Boolean> f) { return filterIterator(it, f); } static <A> IterableIterator<A> filterI(Iterator<A> it, IF1<A, Boolean> f) { return filterIterator(it, f); } static <A> IterableIterator<A> filterI(F1<A, Boolean> f, Iterator<A> it) { return filterIterator(f, it); } static <A> IterableIterator<A> filterI(IF1<A, Boolean> f, Iterator<A> it) { return filterIterator(f, it); } static <A> IterableIterator<A> filterI(IF1<A, Boolean> f, Iterable<A> it) { return filterIterator(f, iterator(it)); } static <A> Iterator<A> iterator(Iterable<A> 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 <A> IterableIterator<A> 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<String> caseInsensitiveSet() { return caseInsensitiveSet_treeSet(); } static TreeSet<String> caseInsensitiveSet(Collection<String> c) { return caseInsensitiveSet_treeSet(c); } static <A> TreeSet<A> treeSet() { return new TreeSet(); } static int indexOfIC(List<String> a, String b) { return indexOfIgnoreCase(a, b); } static int indexOfIC(List<String> 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<String, Integer> listIndexCI(List<String> l) { Map<String, Integer> map = ciMap(); for (int i = 0; i < l(l); i++) map.put(l.get(i), i); return map; } static List<String> englishMonthNames() { return englishMonthName_data; } static <A> A or(A a, A b) { return a != null ? a : b; } static int countPrecedingTokens(ListAndIndex<String> l) { return l == null ? 0 : l.idx/2; } static IterableIterator<Integer> countIterator_inclusive(final int a, final int b) { return countIterator_exclusive(a, b+1); } static <A> IterableIterator<A> countIterator_inclusive(int a, int b, IF1<Integer, A> f) { return countIterator_inclusive(a, b, 1, f); } static <A> IterableIterator<A> countIterator_inclusive(int a, int b, int step, IF1<Integer, A> f) { return countIterator_inclusive_step(a, b, 1, f); } static <A> IterableIterator<A> countIterator_inclusive(double a, double b, double step, IF1<Double, A> f) { return countIterator_inclusive_step(a, b, step, f); } static ParsedWithTokens<String> pwt_raw(List<String> tok, int iStart, int iEnd) { return new ParsedWithTokens<String>(joinSubList(tok, iStart, iEnd), tok, iStart, iEnd); } static int countRemainingTokens(ListAndIndex<String> l) { return l == null ? 0 : (l.size()-l.idx)/2; } static List<String> 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 <A> List<A> 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 <A, B> Map<A, B> 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 <A> void listSet(List<A> l, int i, A a, A emptyElement) { if (i < 0) return; while (i >= l(l)) l.add(emptyElement); l.set(i, a); } static <A> void listSet(List<A> l, int i, A a) { listSet(l, i, a, null); } static <A> List<A> uniquifyList(Collection<A> l) { if (l == null) return null; if (l(l) < 2) return asList(l); HashSet<A> set = new HashSet(); List<A> out = new ArrayList(); for (A a : l) if (set.add(a)) out.add(a); return out; } static <A> List<A> withoutNulls(Iterable<A> l) { if (l instanceof List) if (!containsNulls((List) l)) return ((List) l); List<A> l2 = new ArrayList(); for (A a : l) if (a != null) l2.add(a); return l2; } static <A, B> Map<A, B> withoutNulls(Map<A, B> map) { Map<A, B> 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 <A> List<A> withoutNulls(A[] l) { List<A> 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<Class, ArrayList<Method>> callF_cache = newDangerousWeakHashMap(); static <A> A callF(F0<A> f) { return f == null ? null : f.get(); } static <A, B> B callF(F1<A, B> f, A a) { return f == null ? null : f.get(a); } static <A> A callF(IF0<A> f) { return f == null ? null : f.get(); } static <A, B> B callF(IF1<A, B> f, A a) { return f == null ? null : f.get(a); } static <A, B> B callF(A a, IF1<A, B> f) { return f == null ? null : f.get(a); } static <A, B, C> C callF(IF2<A, B, C> f, A a, B b) { return f == null ? null : f.get(a, b); } static <A> void callF(VF1<A> f, A a) { if (f != null) f.get(a); } static <A> void callF(A a, IVF1<A> f) { if (f != null) f.get(a); } static <A> void callF(IVF1<A> 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<Method> 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<Method> callF_makeCache(Class c) { ArrayList<Method> 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 <A, B> Set<Map.Entry<A,B>> _entrySet(Map<A, B> map) { return map == null ? Collections.EMPTY_SET : map.entrySet(); } static <A> List<A> concatLists(Iterable<A>... lists) { List<A> l = new ArrayList(); if (lists != null) for (Iterable<A> list : lists) addAll(l, list); return l; } static <A> List<A> concatLists(Collection<? extends Iterable<A>> lists) { List<A> l = new ArrayList(); if (lists != null) for (Iterable<A> 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 <A, B> List<B> map(Iterable<A> l, F1<A, B> f) { return map(f, l); } static <A, B> List<B> map(F1<A, B> f, Iterable<A> l) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(callF(f, o)); } return x; } static <A, B> List<B> map(IF1<A, B> f, Iterable<A> l) { return map(l, f); } static <A, B> List<B> map(Iterable<A> l, IF1<A, B> f) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(f.get(o)); } return x; } static <A, B> List<B> map(IF1<A, B> f, A[] l) { return map(l, f); } static <A, B> List<B> map(A[] l, IF1<A, B> 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 <A, B, C> List<C> map(Map<A, B> map, IF2<A, B, C> f) { return map(map, (Object) f); } // new magic alias for mapLL - does it conflict? static <A, B> List<A> map(IF1<A, B> 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<Integer> codeTokenIndices(List<String> 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 <A, B> List<B> mapNonNulls(Iterable<A> l, F1<A, B> f) { return mapNonNulls(f, l); } static <A, B> List<B> mapNonNulls(F1<A, B> f, Iterable<A> l) { List x = new ArrayList(); if (l != null) for (Object o : l) addIfNotNull(x, callF(f, o)); return x; } static <A, B> List<B> mapNonNulls(A[] l, IF1<A, B> f) { return mapNonNulls(f, l); } static <A, B> List<B> mapNonNulls(Iterable<A> l, IF1<A, B> f) { List x = emptyList(l); if (l != null) for (A o : l) addIfNotNull(x, f.get(o)); return x; } static <A, B> List<B> mapNonNulls(IF1<A, B> f, Iterable<A> l) { return mapNonNulls(l, f); } static String joinNemptiesWithColon(String... strings) { return joinNempties(": ", strings); } static String joinNemptiesWithColon(Collection<String> 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 <A> List<A> 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 <A> IterableIterator<A> filterIterator(final Iterator<A> it, final F1<A, Boolean> f) { if (it == null) return null; return iff(new F0<Object>() { 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 <A> IterableIterator<A> filterIterator(final Iterator<A> it, final IF1<A, Boolean> f) { if (it == null) return null; return iff(new F0<Object>() { 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 <A> IterableIterator<A> filterIterator(final F1<A, Boolean> f, final Iterator<A> it) { return filterIterator(it, f); } static <A> IterableIterator<A> filterIterator(Collection<A> l, IF1<A, Boolean> f) { if (l == null) return null; Iterator<A> it = iterator(l); return iff(new F0<Object>() { 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 <A> IterableIterator<A> filterIterator(IF1<A, Boolean> f, Iterator<A> 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 <A> IterableIterator<A> emptyIterableIterator() { return emptyIterableIterator_instance; } static <A> int iteratorCount_int_close(Iterator<A> 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<String> caseInsensitiveSet_treeSet() { return new TreeSet(caseInsensitiveComparator()); } static TreeSet<String> caseInsensitiveSet_treeSet(Collection<String> c) { return toCaseInsensitiveSet_treeSet(c); } // works on lists and strings and null static int indexOfIgnoreCase(List<String> a, String b) { return indexOfIgnoreCase(a, b, 0); } static int indexOfIgnoreCase(List<String> 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 <A> TreeMap<String, A> ciMap() { return caseInsensitiveMap(); } static IterableIterator<Integer> countIterator_exclusive(int b) { return countIterator_exclusive(0, b); } static IterableIterator<Integer> countIterator_exclusive(int a, int b) { return new IterableIterator<Integer>() { int i = a; public boolean hasNext() { return i < b; } public Integer next() { return i++; } }; } static <A> IterableIterator<A> countIterator_exclusive(int b, IF1<Integer, A> f) { return countIterator_exclusive(0, b, f); } static <A> IterableIterator<A> countIterator_exclusive(int a, int b, IF1<Integer, A> f) { return mapI_if1(f, countIterator_exclusive(a, b)); } static IterableIterator<Integer> countIterator_inclusive_step(int a, final int b, int step) { assertTrue("step > 0", step > 0); return new IterableIterator<Integer>() { int i = a; public boolean hasNext() { return i <= b; } public Integer next() { var j = i; i += step; return j; } }; } static IterableIterator<Double> countIterator_inclusive_step(double a, double b, double step) { assertTrue("step > 0", step > 0); return new IterableIterator<Double>() { double i = a; public boolean hasNext() { return i <= b; } public Double next() { var j = i; i += step; return j; } }; } static <A> IterableIterator<A> countIterator_inclusive_step(double a, double b, double step, IF1<Double, A> f) { return mapI_if1(f, countIterator_inclusive_step(a, b, step)); } static <A> IterableIterator<A> countIterator_inclusive_step(int a, int b, int step, IF1<Integer, A> f) { return mapI_if1(f, countIterator_inclusive_step(a, b, step)); } static String joinSubList(List<String> l, int i, int j) { return join(subList(l, i, j)); } static String joinSubList(List<String> l, int i) { return join(subList(l, i)); } static WeakHasherMap<Symbol, Boolean> symbol_map = new WeakHasherMap(new Hasher<Symbol>() { 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 <A> ArrayList<A> asList(A[] a) { return a == null ? new ArrayList<A>() : new ArrayList<A>(Arrays.asList(a)); } static ArrayList<Integer> asList(int[] a) { if (a == null) return null; ArrayList<Integer> l = emptyList(a.length); for (int i : a) l.add(i); return l; } static ArrayList<Long> asList(long[] a) { if (a == null) return null; ArrayList<Long> l = emptyList(a.length); for (long i : a) l.add(i); return l; } static ArrayList<Float> asList(float[] a) { if (a == null) return null; ArrayList<Float> l = emptyList(a.length); for (float i : a) l.add(i); return l; } static ArrayList<Double> asList(double[] a) { if (a == null) return null; ArrayList<Double> l = emptyList(a.length); for (double i : a) l.add(i); return l; } static ArrayList<Short> asList(short[] a) { if (a == null) return null; ArrayList<Short> l = emptyList(a.length); for (short i : a) l.add(i); return l; } static <A> ArrayList<A> asList(Iterator<A> it) { ArrayList l = new ArrayList(); if (it != null) while (it.hasNext()) l.add(it.next()); return l; } // disambiguation static <A> ArrayList<A> asList(IterableIterator<A> s) { return asList((Iterator) s); } static <A> ArrayList<A> asList(Iterable<A> 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 <A> ArrayList<A> asList(Enumeration<A> e) { ArrayList l = new ArrayList(); if (e != null) while (e.hasMoreElements()) l.add(e.nextElement()); return l; } static <A> List<A> asList(Pair<A, A> 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 <A, B> Set<A> keys(Map<A, B> map) { return map == null ? new HashSet() : map.keySet(); } // convenience shortcut for keys_gen static Set keys(Object map) { return keys((Map) map); } static <A, B> Set<A> keys(MultiMap<A, B> mm) { return mm.keySet(); } static String getClassName(Object o) { return o == null ? "null" : o instanceof Class ? ((Class) o).getName() : o.getClass().getName(); } static <A, B> Map<A, B> newDangerousWeakHashMap() { return _registerDangerousWeakMap(synchroMap(new WeakHashMap())); } // initFunction: voidfunc(Map) - is called initially, and after clearing the map static <A, B> Map<A, B> 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 <A, B extends A> void addAll(Collection<A> c, Iterable<B> b) { if (c != null && b != null) for (A a : b) c.add(a); } static <A, B extends A> boolean addAll(Collection<A> c, Collection<B> b) { return c != null && b != null && c.addAll(b); } static <A, B extends A> boolean addAll(Collection<A> c, B... b) { return c != null && b != null && c.addAll(Arrays.asList(b)); } static <A, B> Map<A, B> addAll(Map<A, B> a, Map<? extends A,? extends B> 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 <A> ArrayList<A> emptyList(Class<A> 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<Thread, Object> ping_actions = newWeakHashMap(); static ThreadLocal<Boolean> 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<Integer> countIterator_exclusive_step(final int a, final int b, final int step) { assertTrue("step > 0", step > 0); return new IterableIterator<Integer>() { int i = a; public boolean hasNext() { return i < b; } public Integer next() { var j = i; i += step; return j; } }; } static IterableIterator<Double> countIterator_exclusive_step(double a, double b, double step) { assertTrue("step > 0", step > 0); return new IterableIterator<Double>() { double i = a; public boolean hasNext() { return i < b; } public Double next() { var j = i; i += step; return j; } }; } static <A> IterableIterator<A> countIterator_exclusive_step(double a, double b, double step, IF1<Double, A> f) { return mapI_if1(f, countIterator_exclusive_step(a, b, step)); } static <A> boolean addIfNotNull(Collection<A> 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 <A> IterableIterator<A> 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 <A> 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<Method> 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<Method> 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<String> caseInsensitiveComparator() { return betterCIComparator(); } static TreeSet<String> toCaseInsensitiveSet_treeSet(Iterable<String> c) { if (isCISet(c)) return (TreeSet) c; TreeSet<String> set = caseInsensitiveSet_treeSet(); addAll(set, c); return set; } static TreeSet<String> toCaseInsensitiveSet_treeSet(String... x) { TreeSet<String> 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 <A> TreeMap<String, A> caseInsensitiveMap() { return new TreeMap(caseInsensitiveComparator()); } static class mapI_if1_It<A, B> extends IterableIterator<B> { IF1<A, B> f; Iterator<A> i; mapI_if1_It() {} mapI_if1_It(IF1<A, B> f, Iterator<A> 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 <A, B> IterableIterator<B> mapI_if1(IF1<A, B> f, Iterable<A> i) { return new mapI_if1_It(f, i.iterator()); } static <A, B> IterableIterator<B> mapI_if1(Iterable<A> i, IF1<A, B> 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 <A> List<A> subList(List<A> l, int startIndex) { return subList(l, startIndex, l(l)); } static <A> List<A> subList(int startIndex, List<A> l) { return subList(l, startIndex); } static <A> List<A> subList(int startIndex, int endIndex, List<A> l) { return subList(l, startIndex, endIndex); } static <A> List<A> subList(List<A> 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 <A> IterableIterator<A> iteratorFromFunction_withEndMarker(final Object f) { class IFF extends IterableIterator<A> { 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 <A> IterableIterator<A> iteratorFromFunction_withEndMarker(final F0 f) { return iteratorFromFunction_withEndMarker_f0(f); } static List<Pair> _registerDangerousWeakMap_preList; static <A> A _registerDangerousWeakMap(A map) { return _registerDangerousWeakMap(map, null); } static <A> A _registerDangerousWeakMap(A map, Object init) { callF(init, map); if (init instanceof String) { final String f = (String) init; init = new VF1<Map>() { 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 <A, B> Map<A, B> synchroMap(Map<A, B> 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<String> classNames(Collection l) { return getClassNames(l); } static List<String> 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<Object> print_byThread; // special handling by thread - prefers F1<S, Bool> static volatile Object print_allThreads; static volatile Object print_preprocess; static void print() { print(""); } static <A> A print(String s, A o) { print(combinePrintParameters(s, o)); return o; } // slightly overblown signature to return original object... static <A> 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 <A, B> Map<A, B> 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<String, Set> vm_busListenersByMessage_live_cache; static Map<String, Set> vm_busListenersByMessage_live() { if (vm_busListenersByMessage_live_cache == null) vm_busListenersByMessage_live_cache = vm_busListenersByMessage_live_load(); return vm_busListenersByMessage_live_cache; } static Map<String, Set> vm_busListenersByMessage_live_load() { return vm_generalHashMap("busListenersByMessage"); } static Class javax() { return getJavaX(); } static final Map<Class, _MethodCache> 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 <A> String joinWithComma(Collection<A> 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<String> { 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<String> 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<String, Boolean> f) { return print_byThread().get() == null ? tempInterceptPrint(f) : null; } static <A> IterableIterator<A> iteratorFromFunction_withEndMarker_f0(final F0<A> f) { class IFF2 extends IterableIterator<A> { 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<String, List<Method>> 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<Method> 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 <A> List<A> synchroList() { return synchroList(new ArrayList<A>()); } static <A> List<A> synchroList(List<A> l) { return Collections.synchronizedList(l); } static <A> A assertNotNull(A a) { assertTrue(a != null); return a; } static <A> A assertNotNull(String msg, A a) { assertTrue(msg, a != null); return a; } static Map synchroHashMap() { return synchronizedMap(new HashMap()); } static List<String> getClassNames(Collection l) { List<String> 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> A getThreadLocal(ThreadLocal<A> tl) { return tl == null ? null : tl.get(); } static <A> A getThreadLocal(ThreadLocal<A> tl, A defaultValue) { return or(getThreadLocal(tl), defaultValue); } static ThreadLocal<Object> 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> 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<Runnable> newPing_actionTL; static x30_pkg.x30_util.BetterThreadLocal<Runnable> 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<Runnable>(); 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 <A> Collection<A> unnull(Collection<A> l) { return l == null ? emptyList() : l; } static <A> List<A> unnull(List<A> 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 <A, B> Map<A, B> unnull(Map<A, B> l) { return l == null ? emptyMap() : l; } static <A> Iterable<A> unnull(Iterable<A> i) { return i == null ? emptyList() : i; } static <A> 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 <A, B> Pair<A, B> unnull(Pair<A, B> 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 <A> ArrayList<A> cloneList(Iterable<A> l) { return l instanceof Collection ? cloneList((Collection) l) : asList(l); } static <A> ArrayList<A> cloneList(Collection<A> l) { if (l == null) return new ArrayList(); synchronized(collectionMutex(l)) { return new ArrayList<A>(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> A[] arrayOfType(Class<A> type, int n) { return makeArray(type, n); } static <A> A[] arrayOfType(int n, Class<A> type) { return arrayOfType(type, n); } static List<String> allToString(Iterable c) { List<String> l = new ArrayList(); for (Object o : unnull(c)) l.add(str(o)); return l; } static List<String> allToString(Object[] c) { List<String> 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<Object> 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<String, Boolean> f) { return tempSetThreadLocal(print_byThread(), f); } static List<Class> getClasses(Object[] array) { List<Class> l = emptyList(l(array)); for (Object o : array) l.add(_getClass(o)); return l; } static <A, B> void multiMapPut(Map<A, List<B>> map, A a, B b) { List<B> l = map.get(a); if (l == null) map.put(a, l = new ArrayList()); l.add(b); } static <A, B> void multiMapPut(MultiMap<A, B> mm, A key, B value) { if (mm != null && key != null && value != null) mm.put(key, value); } static Map synchronizedMap() { return synchroMap(); } static <A, B> Map<A, B> synchronizedMap(Map<A, B> 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=<hidden>"); } static String hideCredentials(Object o) { return hideCredentials(str(o)); } static <A> int indexOf(List<A> 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 <A> int indexOf(List<A> l, int startIndex, A a) { return indexOf(l, a, startIndex); } static <A> int indexOf(List<A> 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 <A> 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 extends Throwable> A printException(A e) { printStackTrace(e); return e; } static <A> A vm_generalMap_getOrCreate(Object key, F0<A> create) { return vm_generalMap_getOrCreate(key, f0ToIF0(create)); } static <A> A vm_generalMap_getOrCreate(Object key, IF0<A> 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> A callF_gen(F0<A> f) { return f == null ? null : f.get(); } static <A, B> B callF_gen(F1<A, B> f, A a) { return f == null ? null : f.get(a); } static <A> A callF_gen(IF0<A> f) { return f == null ? null : f.get(); } static <A, B> B callF_gen(IF1<A, B> f, A a) { return f == null ? null : f.get(a); } static <A, B> B callF_gen(A a, IF1<A, B> f) { return f == null ? null : f.get(a); } static <A, B, C> C callF_gen(IF2<A, B, C> f, A a, B b) { return f == null ? null : f.get(a, b); } static <A> void callF_gen(VF1<A> f, A a) { { if (f != null) f.get(a); } } static <A> void callF_gen(A a, IVF1<A> f) { { if (f != null) f.get(a); } } static <A> void callF_gen(IVF1<A> 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 <A> Set<A> syncIdentityHashSet() { return (Set) synchronizedSet(identityHashSet()); } static Map syncHashMap() { return synchroHashMap(); } static void _onJavaXSet() {} static <A> A[] makeArray(Class<A> type, int n) { return (A[]) Array.newInstance(type, n); } static <A> AutoCloseable tempSetThreadLocal(final ThreadLocal<A> 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<Class, HashMap<S, Field>> 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<Class, HashMap<String, Field>> getOpt_cache = _registerDangerousWeakMap(synchroMap(new getOpt_Map())); //static final Map<Class, HashMap<S, Field>> 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<String, Field> getOpt_getFieldMap(Object o) { Class c = _getClass(o); HashMap<String, Field> 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<String, Field> 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<String, Field> getOpt_makeCache(Class c) { HashMap<String, Field> 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 extends Throwable> 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 <A> IF0<A> f0ToIF0(F0<A> 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 <A, B> B mapPutOrRemove(Map<A, B> 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 <A> Set<A> synchronizedSet() { return synchroHashSet(); } static <A> Set<A> synchronizedSet(Set<A> set) { return Collections.synchronizedSet(set); } static <A> Set<A> identityHashSet() { return Collections.newSetFromMap(new IdentityHashMap()); } static <A> A setThreadLocal(ThreadLocal<A> 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 <A, B> void put(Map<A, B> map, A a, B b) { if (map != null) map.put(a, b); } static <A> void put(List<A> l, int i, A a) { if (l != null && i >= 0 && i < l(l)) l.set(i, a); } static <A, B> B syncMapGet2(Map<A, B> map, A a) { if (map == null) return null; synchronized(collectionMutex(map)) { return map.get(a); } } static <A, B> B syncMapGet2(A a, Map<A, B> 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<String> reflection_classesNotToScan_value = litset( "jdk.internal.loader.URLClassPath" ); static Set<String> 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 <A> Set<A> synchroHashSet() { return synchronizedSet(new HashSet<A>()); } static <A> HashSet<A> 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 <A> HashSet<A> lithashset(A... items) { HashSet<A> 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<String, List<Method>> 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<Method> 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<Method> 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<A> implements IVF1<A> { 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<A> { abstract A get(); } static abstract class F1<A, B> { abstract B get(A a); } // you still need to implement hasNext() and next() static abstract class IterableIterator<A> implements Iterator<A>, Iterable<A> { public Iterator<A> 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<A> extends Var<A> { List<String> 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<String> 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<String> remaining() { return new ListAndIndex(tok, iRemaining); } ListAndIndex<String> start() { return new ListAndIndex(tok, iStart); } int length() { return iRemaining-iStart; } <B> ParsedWithTokens<B> withValue(B b) { return new ParsedWithTokens<B>(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<A,B> { Map<A, List<B>> data = new HashMap<A, List<B>>(); int fullSize; MultiMap() {} MultiMap(boolean useTreeMap) { if (useTreeMap) data = new TreeMap(); } MultiMap(MultiMap<A, B> map) { putAll(map); } MultiMap(Map<A, List<B>> data) { this.data = data;} void put(A key, B value) { synchronized(data) { List<B> 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<B> values) { putAll(key, values); } void addAllIfNotThere(A key, Collection<B> 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<A> keys, B value) { synchronized(data) { for (A key : unnullForIteration(keys)) put(key, value); }} void putAll(A key, Collection<B> values) { synchronized(data) { if (nempty(values)) getActual(key).addAll(values); }} void putAll(Iterable<Pair<A, B>> pairs) { synchronized(data) { for (Pair<A, B> p : unnullForIteration(pairs)) put(p.a, p.b); }} void removeAll(A key, Collection<B> values) { synchronized(data) { for (B value : values) remove(key, value); }} List<B> get(A key) { synchronized(data) { List<B> list = data.get(key); return list == null ? Collections.<B> emptyList() : list; }} List<B> getOpt(A key) { synchronized(data) { return data.get(key); }} List<B> getAndClear(A key) { synchronized(data) { List<B> l = cloneList(data.get(key)); remove(key); return l; }} // returns actual mutable live list // creates the list if not there List<B> getActual(A key) { synchronized(data) { List<B> list = data.get(key); if (list == null) data.put(key, list = _makeEmptyList()); return list; }} void clean(A key) { synchronized(data) { List<B> list = data.get(key); if (list != null && list.isEmpty()) { fullSize -= l(list); data.remove(key); } }} Set<A> keySet() { synchronized(data) { return data.keySet(); }} Set<A> keys() { synchronized(data) { return data.keySet(); }} void remove(A key) { synchronized(data) { fullSize -= l(this.getOpt(key)); data.remove(key); }} final void remove(Pair<A, B> p){ removePair(p); } void removePair(Pair<A, B> p) { if (p != null) remove(p.a, p.b); } void remove(A key, B value) { synchronized(data) { List<B> 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<B> list = get(key); return list.isEmpty() ? null : list.get(0); }} void addAll(MultiMap<A, B> map) { putAll(map); } void putAll(MultiMap<A, B> map) { synchronized(data) { for (A key : map.keySet()) putAll(key, map.get(key)); }} void putAll(Map<A, B> map) { synchronized(data) { if (map != null) for (Map.Entry<A, B> 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<A> reverseGet(B b) { synchronized(data) { List<A> l = new ArrayList(); for (A key : data.keySet()) if (data.get(key).contains(b)) l.add(key); return l; }} Map<A, List<B>> asMap() { synchronized(data) { return cloneMap(data); }} boolean isEmpty() { synchronized(data) { return data.isEmpty(); }} // override in subclasses List<B> _makeEmptyList() { return new ArrayList(); } // returns live lists Collection<List<B>> allLists() { synchronized(data) { return new ArrayList(data.values()); } } Collection<List<B>> values() { return allLists(); } List<B> allValues() { return concatLists(data.values()); } Object mutex() { return data; } public String toString() { return "mm" + str(data); } } static interface IF0<A> { A get(); } static interface Hasher<A> { int hashCode(A a); boolean equals(A a, A b); } static interface IF2<A, B, C> { C get(A a, B b); } static interface IF1<A, B> { B get(A a); } static interface IF3<A, B, C, D> { D get(A a, B b, C c); } static class ListAndIndex<A> implements IFieldsToList{ static final String _fieldOrder = "list idx"; List<A> list; int idx; ListAndIndex() {} ListAndIndex(List<A> 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<A> 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<K,V> extends AbstractMap<K,V> implements Map<K,V> { 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<? super K> 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<K> { 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<? super K> q) { super(k, q); hash = keyHashCode(k); } private /*@Nullable*/ WeakKey create(K k, ReferenceQueue<? super K> 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<WeakKey,V> hash; /* Reference queue for cleared WeakKeys */ private ReferenceQueue<? super K> queue = new ReferenceQueue<K>(); /* 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 <code>WeakHashMap</code> with the given * initial capacity and the given load factor. * * @param initialCapacity the initial capacity of the * <code>WeakHashMap</code> * * @param loadFactor the load factor of the <code>WeakHashMap</code> * * @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<WeakKey,V>(initialCapacity, loadFactor); } /** * Constructs a new, empty <code>WeakHashMap</code> with the given * initial capacity and the default load factor, which is * <code>0.75</code>. * * @param initialCapacity the initial capacity of the * <code>WeakHashMap</code> * * @throws IllegalArgumentException If the initial capacity is less than * zero */ public WeakHasherMap(int initialCapacity) { hash = new HashMap<WeakKey,V>(initialCapacity); } /** * Constructs a new, empty <code>WeakHashMap</code> with the default * capacity and the default load factor, which is <code>0.75</code>. */ public WeakHasherMap() { hash = new HashMap<WeakKey,V>(); } /** * Constructs a new, empty <code>WeakHashMap</code> with the default * capacity and the default load factor, which is <code>0.75</code>. * The <code>WeakHashMap</code> 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<WeakKey,V>(); hasher = h; } /* -- Simple queries -- */ /** * Returns the number of key-value mappings in this map. * <strong>Note:</strong> <em>In contrast to most implementations of the * <code>Map</code> interface, the time required by this operation is * linear in the size of the map.</em> */ /*@Pure*/ @Override public int size() { return entrySet().size(); } /** * Returns <code>true</code> if this map contains no key-value mappings. */ /*@Pure*/ @Override public boolean isEmpty() { return entrySet().isEmpty(); } /** * Returns <code>true</code> 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 <code>key</code>. * If this map does not contain a value for this key, then return * <code>null</code>. * * @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 <code>key</code> maps to the given * <code>value</code>. If the map previously contained a mapping for * <code>key</code> then that mapping is replaced and the previous value is * returned. * * @param key the key that is to be mapped to the given * <code>value</code> * @param value the value to which the given <code>key</code> is to be * mapped * * @return the previous value to which this key was mapped, or * <code>null</code> 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 <code>key</code> 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 <code>null</code> 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<K,V> implements Map.Entry<K,V> { private Map.Entry<WeakKey,V> 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<WeakKey,V> 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<K,V> e /* Object o*/) { // if (! (o instanceof Map.Entry)) return false; // Map.Entry<K,V> e = (Map.Entry<K,V>)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<Map.Entry<K,V>> { Set<Map.Entry<WeakKey,V>> hashEntrySet = hash.entrySet(); @Override public Iterator<Map.Entry<K,V>> iterator() { return new Iterator<Map.Entry<K,V>>() { Iterator<Map.Entry<WeakKey,V>> hashIterator = hashEntrySet.iterator(); Map.Entry<K,V> next = null; @Override public boolean hasNext() { while (hashIterator.hasNext()) { Map.Entry<WeakKey,V> 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<K,V>(ent, k); return true; } return false; } @Override public Map.Entry<K,V> next() { if ((next == null) && !hasNext()) throw new NoSuchElementException(); Map.Entry<K,V> 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<Map.Entry<K,V>> 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<K,V> e = (Map.Entry<K,V>)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<Map.Entry<WeakKey,V>> i = hashEntrySet.iterator(); i.hasNext(); ) { Map.Entry<WeakKey,V> 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<Map.Entry<K,V>> entrySet = null; /** * Returns a <code>Set</code> view of the mappings in this map. */ /*@SideEffectFree*/ @Override public Set<Map.Entry<K,V>> 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<A> { 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<A, B> implements Comparable<Pair<A, B>> { 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<A, B> p) { if (p == null) return 1; int i = ((Comparable<A>) a).compareTo(p.a); if (i != 0) return i; return ((Comparable<B>) b).compareTo(p.b); } } static class Not<A> 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<A> 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<A> implements IVar<A>, ISetter<A> { 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<A> { void set(A a); } static interface IVar<A> extends IF0<A> { 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<Class> allInterfacesImplementedBy(Class c) { if (c == null) return null; HashSet<Class> set = new HashSet(); allInterfacesImplementedBy_find(c, set); return set; } static void allInterfacesImplementedBy_find(Class c, Set<Class> 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<String> quoteAll(Collection<String> l) { List<String> 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 <A> ArrayList<A> toList(A[] a) { return asList(a); } static ArrayList<Integer> toList(int[] a) { return asList(a); } static <A> ArrayList<A> toList(Set<A> s) { return asList(s); } static <A> ArrayList<A> toList(Iterable<A> 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<String> tok, int i, int j, String s) { clearAllTokens(tok, i+1, j); tok.set(i, s); } static void replaceTokens(List<String> tok, String s) { clearAllTokens(tok, 1, l(tok)); tok.set(0, s); } static <A, B> Map<A, B> putAll(Map<A, B> a, Map<? extends A,? extends B> b) { if (a != null && b != null) a.putAll(b); return a; } static <A, B> MultiMap<A, B> putAll(MultiMap<A, B> a, Map<? extends A,? extends B> b) { if (a != null) a.putAll((Map) b); return a; } static <A, B> Map<A, B> putAll(Map<A, B> a, Object... b) { if (a != null) litmap_impl(a, b); return a; } static <A> void remove(List<A> l, int i) { if (l != null && i >= 0 && i < l(l)) l.remove(i); } static <A> void remove(Collection<A> l, A a) { if (l != null) l.remove(a); } static <A, B> B remove(Map<A, B> map, Object a) { return map == null ? null : map.remove(a); } static void remove(BitSet bs, int i) { bs.clear(i); } static <A> A getAndClear(IVar<A> v) { A a = v.get(); v.set(null); return a; } static <A, B> Set<A> keySet(Map<A, B> map) { return map == null ? new HashSet() : map.keySet(); } static Set keySet(Object map) { return keys((Map) map); } static <A, B> Set<A> keySet(MultiMap<A, B> mm) { return mm.keySet(); } static <A, B> int keysSize(MultiMap<A, B> mm) { return lKeys(mm); } static <A> A reverseGet(List<A> l, int idx) { if (l == null || idx < 0) return null; int n = l(l); return idx < n ? l.get(n-1-idx) : null; } static <A, B> Map<A, B> cloneMap(Map<A, B> 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 <A, B> List<B> cloneMap(Iterable<A> l, IF1<A, B> f) { List x = emptyList(l); if (l != null) for (A o : cloneList(l)) x.add(f.get(o)); return x; } static <A, B> Collection<B> values(Map<A, B> map) { return map == null ? emptyList() : map.values(); } // convenience shortcut for values_gen static Collection values(Object map) { return values((Map) map); } static <A, B> Collection<B> values(MultiMap<A, B> 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, B> A hashMap_findKey(HashMap<A, B> map, Object key) { try { if (hashMap_findKey_method == null) hashMap_findKey_method = findMethodNamed(HashMap.class, "getNode"); Map.Entry<A, B> entry = (Map.Entry) hashMap_findKey_method.invoke(map, hashMap_internalHash(key), key); // java.util.Map.Entry<A, B> 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> 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<Method> 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<Method> 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<String> tok) { for (int i = 0; i < tok.size(); i++) tok.set(i, ""); } static void clearAllTokens(List<String> 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 <A, B> int lKeys(MultiMap<A, B> 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> A[] dropLast(A[] a) { return dropLast(a, 1); } static <A> 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 <A> List<A> dropLast(List<A> l) { return subList(l, 0, l(l)-1); } static <A> List<A> dropLast(int n, List<A> l) { return subList(l, 0, l(l)-n); } static <A> List<A> dropLast(Iterable<A> 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 <A> List<A> dropFirst(List<A> l) { return dropFirst(1, l); } static <A> List<A> dropFirst(int n, Iterable<A> i) { return dropFirst(n, toList(i)); } static <A> List<A> dropFirst(Iterable<A> i) { return dropFirst(toList(i)); } static <A> List<A> dropFirst(int n, List<A> l) { return n <= 0 ? l : new ArrayList(l.subList(Math.min(n, l.size()), l.size())); } static <A> List<A> dropFirst(List<A> 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 <A, B> List<B> map_ping(Iterable<A> l, F1<A, B> f) { return map_ping(f, l); } static <A, B> List<B> map_ping(F1<A, B> f, Iterable<A> l) { List x = emptyList(l); if (l != null) for (A o : l) x.add(callF(f, o)); return x; } static <A, B> List<B> map_ping(IF1<A, B> f, Iterable<A> l) { return map_ping(l, f); } static <A, B> List<B> map_ping(Iterable<A> l, IF1<A, B> f) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(f.get(o)); } return x; } static <A, B> List<B> map_ping(IF1<A, B> f, A[] l) { return map_ping(l, f); } static <A, B> List<B> map_ping(A[] l, IF1<A, B> 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 <A, B, C> List<C> map_ping(Map<A, B> map, IF2<A, B, C> 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 <A, B> LinkedHashMap<A, B> asLinkedHashMap(Map<A, B> map) { if (map instanceof LinkedHashMap) return (LinkedHashMap) map; LinkedHashMap<A, B> m = new LinkedHashMap(); if (map != null) synchronized(collectionMutex(map)) { m.putAll(map); } return m; } static <A> 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 <A> int lastIndexOf(List<A> 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 <A> int lastIndexOf(List<A> 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<String> 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> A[] newObjectArrayOfSameType(A[] a) { return newObjectArrayOfSameType(a, a.length); } static <A> A[] newObjectArrayOfSameType(A[] a, int n) { return (A[]) Array.newInstance(a.getClass().getComponentType(), n); } static <A> ArrayList<A> 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<String> toLowerCase(List<String> strings) { List<String> 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<Character, Boolean> 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<StructureHandler> 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<Object, Boolean> 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<Object, Object> markPointer; void markPointer(Object a, Object b) { if (markPointer != null) markPointer.get(a, b); else markPointer_base(a, b); } final void markPointer_fallback(IVF2<Object, Object> _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<A> implements VStack.Computable<A> { 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<A> extends VStackComputableWithStep implements IFieldsToList{ Iterable<A> l; IVF1<A> body; ForEach_vstack() {} ForEach_vstack(Iterable<A> l, IVF1<A> 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<A> 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<Computable> 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<Computable> l) { pushAll(l); } // A is what the function returns interface Computable<A> { 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> A compute(Computable<A> 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<Computable> l) { for (Computable c : unnullForIteration(l)) push(c); } void add(Runnable r) { if (r == null) return; push((stack, subComputationResult) -> r.run()); } } static interface IVF2<A, B> { 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> A vstackCompute(VStack.Computable<A> computation) { return vStackCompute(computation); } static void withCancelPoint(VF1<CancelPoint> 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<CancelPoint> 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> A last(List<A> 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> A last(A[] a) { return l(a) != 0 ? a[l(a)-1] : null; } static <A> A last(Iterator<A> it) { A a = null; while (it.hasNext()) { ping(); a = it.next(); } return a; } static <A> A last(Collection<A> 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<A> it = iterator(l); A a = null; while (it.hasNext()) { ping(); a = it.next(); } return a; } static <A> A last(SortedSet<A> 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<A> extends AbstractSet<A> { // 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<A> root; // root of the BST int size; // size of tree set // BST helper node data type abstract static class Node<A> { A val; // associated data Node<A> left() { return null; } // get left subtree abstract Node<A> setLeft(Node<A> left); // set left subtree - return potentially replaced node Node<A> right() { return null; } // get right subtree abstract Node<A> setRight(Node<A> right); // set right subtree - return potentially replaced node abstract boolean color(); abstract Node<A> convertToBlack(); abstract Node<A> convertToRed(); abstract Node<A> invertColor(); Node<A> 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<A> extends Node<A> { A leftVal; SpecialNode(A leftVal, A val) { this.val = val; this.leftVal = leftVal;} boolean color() { return BLACK; } Node<A> convertToBlack() { return this; } Node<A> convertToRed() { return newNode(RED, val, left(), right()); } Node invertColor() { return convertToRed(); } Node<A> left() { return newLeaf(RED, leftVal); } Node<A> setLeft(Node<A> 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<A> right() { return null; } Node<A> setRight(Node<A> right) { if (right == null) return this; return newNode(color(), val, left(), right); } boolean isLeaf() { return false; } } abstract static class NonLeaf<A> extends Node<A> { // 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<A> left() { return left == null ? null : left instanceof Node ? (Node) left : newLeaf(defaultLeftLeafColor(), (A) left); } void setLeft_noMorph(Node<A> left) { this.left = left != null && left.isLeaf() && left.color() == defaultLeftLeafColor() ? left.val : left; } void setRight_noMorph(Node<A> right) { this.right = right != null && right.isLeaf() && right.color() == defaultRightLeafColor() ? right.val : right; } Node<A> setLeft(Node<A> 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<A> right() { return right == null ? null : right instanceof Node ? (Node) right : newLeaf(defaultRightLeafColor(), (A) right); } Node<A> setRight(Node<A> 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<A> extends NonLeaf<A> { BlackNode(A val) { this.val = val;} boolean color() { return BLACK; } Node<A> convertToBlack() { return this; } Node<A> convertToRed() { return newNode(RED, val, left(), right()); } Node invertColor() { return convertToRed(); } } static class RedNode<A> extends NonLeaf<A> { RedNode(A val) { this.val = val;} boolean color() { return RED; } Node<A> convertToBlack() { return newNode(BLACK, val, left(), right()); } Node<A> convertToRed() { return this; } Node invertColor() { return convertToBlack(); } } abstract static class Leaf<A> extends Node<A> { boolean isLeaf() { return true; } Node<A> setLeft(Node<A> left) { return left == null ? this : newNode(color(), val, left, null); } Node<A> setRight(Node<A> right) { return right == null ? this : newNode(color(), val, null, right); } } static class BlackLeaf<A> extends Leaf<A> { BlackLeaf(A val) { this.val = val;} boolean color() { return BLACK; } Node<A> convertToBlack() { return this; } Node<A> convertToRed() { return new RedLeaf(val); } Node invertColor() { return convertToRed(); } } static class RedLeaf<A> extends Leaf<A> { RedLeaf(A val) { this.val = val;} boolean color() { return RED; } Node<A> convertToBlack() { return new BlackLeaf(val); } Node<A> convertToRed() { return this; } Node invertColor() { return convertToBlack(); } } HyperCompactTreeSet() {} HyperCompactTreeSet(Collection<? extends A> 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 <A> boolean isRed(Node<A> x) { return x != null && x.color() == RED; } static <A> Node<A> newLeaf(boolean color, A val) { return color == RED ? new RedLeaf(val) : new BlackLeaf(val); } static <A> Node<A> newNode(boolean color, A val, Node<A> left, Node<A> 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<A> put(Node<A> 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<A> 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<A> 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<A> rotateRight(Node<A> h) { // assert (h != null) && isRed(h.left()); Node<A> 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<A> rotateLeft(Node<A> h) { // assert (h != null) && isRed(h.right()); Node<A> 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<A> flipColors(Node<A> 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<A> moveRedLeft(Node<A> 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<A> moveRedRight(Node<A> 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<A> balance(Node<A> 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<A> 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<A> 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<A> x, A key) { x = find(x, key); return x == null ? null : x.val; } Node<A> find(Node<A> 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<A> 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<A> 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<A> 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<A> min(Node<A> x) { // assert x != null; while (x.left() != null) x = x.left(); return x; } private Node<A> deleteMin(Node<A> 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<A> iterator() { return new MyIterator(); } class MyIterator extends IterableIterator<A> { List<Node<A>> path = new ArrayList(); MyIterator() { fetch(root); } void fetch(Node<A> 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<A> 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<A> 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<A> ceiling(Node<A> 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<A> t = ceiling(x.left(), key); if (t != null) return t; else return x; } public A floor(A key) { key = (A) sentinel(key); Node<A> 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<A> floor(Node<A> 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<A> 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<NonLeaf> unoptimizedNodes() { List<NonLeaf> out = new ArrayList(); findUnoptimizedNodes(out); return out; } void findUnoptimizedNodes(List<NonLeaf> out) { findUnoptimizedNodes(root, out); } void findUnoptimizedNodes(Node node, List<NonLeaf> 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<A> compact() { return new HyperCompactTreeSet(this); } } static long toMS(double seconds) { return (long) (seconds*1000); } static <A> A vStackCompute(VStack.Computable<A> 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> A find(Collection<A> c, Object... data) { for (A x : c) if (checkFields(x, data)) return x; return null; } static <A> A println(A a) { return print(a); } static <A> A popLast(List<A> l) { return liftLast(l); } static <A> List<A> popLast(int n, List<A> l) { return liftLast(n, l); } static double floor(double d) { return Math.floor(d); } static <A> A optCast(Class<A> 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> A liftLast(List<A> l) { if (empty(l)) return null; int i = l(l)-1; A a = l.get(i); l.remove(i); return a; } static <A> List<A> liftLast(int n, List<A> l) { int i = l(l)-n; List<A> 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 <A> List<A> cloneSubList(List<A> l, int startIndex, int endIndex) { return newSubList(l, startIndex, endIndex); } static <A> List<A> cloneSubList(List<A> l, int startIndex) { return newSubList(l, startIndex); } static <A> List<A> newSubList(List<A> l, int startIndex, int endIndex) { return cloneList(subList(l, startIndex, endIndex)); } static <A> List<A> newSubList(List<A> 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); } } }