@Override public void keyTyped(final KeyEvent e) { if (undo == null || control(e) || DELNEXT.is(e) || DELPREV.is(e) || ESCAPE.is(e)) return; text.pos(text.cursor()); // string to be added String ch = String.valueOf(e.getKeyChar()); // remember if marked text is to be deleted boolean del = true; final byte[] txt = text.text(); if (TAB.is(e)) { if (text.marked()) { // check if lines are to be indented final int s = Math.min(text.pos(), text.start()); final int l = Math.max(text.pos(), text.start()) - 1; for (int p = s; p <= l && p < txt.length; p++) del &= txt[p] != '\n'; if (!del) { text.indent(s, l, e.isShiftDown()); ch = null; } } else { boolean c = true; for (int p = text.pos() - 1; p >= 0 && c; p--) { final byte b = txt[p]; c = ws(b); if (b == '\n') break; } if (c) ch = " "; } } // delete marked text if (text.marked() && del) text.delete(); if (ENTER.is(e)) { // adopt indentation from previous line final StringBuilder sb = new StringBuilder(1).append(e.getKeyChar()); int s = 0; for (int p = text.pos() - 1; p >= 0; p--) { final byte b = txt[p]; if (b == '\n') break; if (b == '\t') { s += 2; } else if (b == ' ') { s++; } else { s = 0; } } for (int p = 0; p < s; p++) sb.append(' '); ch = sb.toString(); } if (ch != null) text.add(ch); text.setCaret(); rend.calc(); showCursor(2); e.consume(); }
@Override public final void mouseDragged(final MouseEvent e) { if (!SwingUtilities.isLeftMouseButton(e)) return; // selection mode select(e.getPoint(), false); final int y = Math.max(20, Math.min(e.getY(), getHeight() - 20)); if (y != e.getY()) scroll.pos(scroll.pos() + e.getY() - y); }
/** * Returns a pre value. * * @param id unique node id * @return pre value or -1 if id was not found */ final int preold(final int id) { // find pre value in table for (int p = Math.max(0, id); p < meta.size; ++p) if (id == id(p)) return p; final int ps = Math.min(meta.size, id); for (int p = 0; p < ps; ++p) if (id == id(p)) return p; // id not found return -1; }
/** * Prints the specified range of the table. * * @param data data reference * @param s first node to be printed * @param e last node to be printed * @return table */ public static byte[] table(final Data data, final int s, final int e) { final TokenBuilder tb = new TokenBuilder(); final int ps = Math.max(0, s); final int pe = Math.min(data.meta.size, e); final Table table = th(); for (int p = ps; p < pe; ++p) table(table, data, p); tb.add(table.finish()); final byte[] ns = data.ns.table(ps, pe); if (ns.length != 0) tb.add(NL).add(ns).add(data.ns.toString(ps, pe)).add(NL); return tb.finish(); }
/** * Draws the specified string. * * @param g graphics reference * @param s text * @param x x coordinate * @param y y coordinate * @param w width * @param fs font size */ public static void chopString( final Graphics g, final byte[] s, final int x, final int y, final int w, final int fs) { if (w < 12) return; final int[] cw = fontWidths(g.getFont()); int j = s.length; try { int l = 0; int fw = 0; for (int k = 0; k < j; k += l) { final int ww = width(g, cw, cp(s, k)); if (fw + ww >= w - 4) { j = Math.max(1, k - l); if (k > 1) fw -= width(g, cw, cp(s, k - 1)); g.drawString("..", x + fw, y + fs); break; } fw += ww; l = cl(s, k); } } catch (final Exception ex) { Util.debug(ex); } g.drawString(string(s, 0, j), x, y + fs); }
@Override public void keyTyped(final KeyEvent e) { if (!hist.active() || control(e) || DELNEXT.is(e) || DELPREV.is(e) || ESCAPE.is(e) || CUT2.is(e)) return; final int caret = editor.pos(); // remember if marked text is to be deleted final StringBuilder sb = new StringBuilder(1).append(e.getKeyChar()); final boolean indent = TAB.is(e) && editor.indent(sb, e.isShiftDown()); // delete marked text final boolean selected = editor.selected() && !indent; if (selected) editor.delete(); final int move = ENTER.is(e) ? editor.enter(sb) : editor.add(sb, selected); // refresh history and adjust cursor position hist.store(editor.text(), caret, editor.pos()); if (move != 0) editor.pos(Math.min(editor.size(), caret + move)); // adjust text height scrollCode.invokeLater(true); e.consume(); }
/** * Adds an attribute entry to the internal update buffer. * * @param pre pre value * @param dist parent distance * @param name attribute name * @param value attribute value * @param uri namespace uri reference * @param ne namespace flag */ public final void attr( final int pre, final int dist, final int name, final byte[] value, final int uri, final boolean ne) { // add attribute to text storage final int i = newID(); final long v = index(pre, i, value, ATTR); final int n = ne ? 1 << 7 : 0; s(Math.min(IO.MAXATTS, dist) << 3 | ATTR); s(n | (byte) (name >> 8)); s(name); s(v >> 32); s(v >> 24); s(v >> 16); s(v >> 8); s(v); s(0); s(0); s(0); s(uri); s(i >> 24); s(i >> 16); s(i >> 8); s(i); }
/** * Adds an element entry to the internal update buffer. * * @param dist parent distance * @param name tag name index * @param asize number of attributes * @param size node size * @param uri namespace uri reference * @param ne namespace flag */ public final void elem( final int dist, final int name, final int asize, final int size, final int uri, final boolean ne) { // build and insert new entry final int i = newID(); final int n = ne ? 1 << 7 : 0; s(Math.min(IO.MAXATTS, asize) << 3 | ELEM); s(n | (byte) (name >> 8)); s(name); s(uri); s(dist >> 24); s(dist >> 16); s(dist >> 8); s(dist); s(size >> 24); s(size >> 16); s(size >> 8); s(size); s(i >> 24); s(i >> 16); s(i >> 8); s(i); }
@Override public byte[] month(final int n, final int min, final int max) { final TokenBuilder tb = new TokenBuilder(); tb.add(substring(MONTHS[n], 0, Math.max(3, max))); while (tb.size() < min) tb.add(' '); return tb.finish(); }
/** * Performs a wildcard search for the specified token. * * @param token token to look for * @return iterator */ private synchronized IndexIterator wc(final byte[] token) { final FTIndexIterator it = FTIndexIterator.FTEMPTY; final FTWildcard wc = new FTWildcard(token); if (!wc.parse()) return it; final IntList pr = new IntList(); final IntList ps = new IntList(); final byte[] pref = wc.prefix(); final int pl = pref.length, tl = tp.length; final int l = Math.min(tl - 1, wc.max()); for (int ti = pl; ti <= l; ti++) { int i = tp[ti]; if (i == -1) continue; int c = ti + 1; int e = -1; while (c < tl && e == -1) e = tp[c++]; i = find(pref, i, e, ti); while (i < e) { final byte[] t = inY.readBytes(i, ti); if (!startsWith(t, pref)) break; if (wc.match(t)) { inZ.cursor(pointer(i, ti)); final int s = size(i, ti); for (int d = 0; d < s; d++) { pr.add(inZ.readNum()); ps.add(inZ.readNum()); } } i += ti + ENTRY; } } return iter(new FTCache(pr, ps), token); }
/** * Draws a visualization tooltip. * * @param g graphics reference * @param tt tooltip label * @param x horizontal position * @param y vertical position * @param w width * @param c color color depth */ public static void drawTooltip( final Graphics g, final String tt, final int x, final int y, final int w, final int c) { final int tw = width(g, tt); final int th = g.getFontMetrics().getHeight(); final int xx = Math.min(w - tw - 8, x); g.setColor(color(c)); g.fillRect(xx - 1, y - th, tw + 4, th); g.setColor(BACK); g.drawString(tt, xx, y - 4); }
/** * Inserts the specified UTF8 character. * * @param pos insertion position * @param cp the character to be added * @return self reference */ public TokenBuilder insert(final int pos, final int cp) { final int s = size; final int cl = chars.length; final int l = cp <= 0x7F ? 1 : cp <= 0x7FF ? 2 : cp <= 0xFFF ? 3 : 4; if (s + l > cl) chars = Arrays.copyOf(chars, Math.max(s + l, (int) (cl * Array.RESIZE))); Array.move(chars, pos, l, size - pos); size = pos; add(cp); size = s + l; return this; }
@Override public synchronized int costs(final IndexToken it) { final byte[] tok = it.get(); if (tok.length > data.meta.maxlen) return Integer.MAX_VALUE; // estimate costs for queries which stretch over multiple index entries final FTOpt opt = ((FTLexer) it).ftOpt(); if (opt.is(FZ) || opt.is(WC)) return Math.max(1, data.meta.size >> 4); return entry(tok).size; }
/** * Performs a fuzzy search for the specified token with a maximum number of errors. * * @param token token to look for * @param k number of errors allowed * @return iterator */ private synchronized IndexIterator fuzzy(final byte[] token, final int k) { FTIndexIterator it = FTIndexIterator.FTEMPTY; final int tokl = token.length, tl = tp.length; final int e = Math.min(tl - 1, tokl + k); int s = Math.max(1, tokl - k) - 1; while (++s <= e) { int p = tp[s]; if (p == -1) continue; int t = s + 1, r = -1; while (t < tl && r == -1) r = tp[t++]; while (p < r) { if (ls.similar(inY.readBytes(p, s), token, k)) { it = FTIndexIterator.union(iter(pointer(p, s), size(p, s), inZ, token), it); } p += s + ENTRY; } } return it; }
/** * Calculates axis caption depending on view width / height. * * @param space space of view axis available for captions */ void calcCaption(final int space) { if (type == Kind.DBL || type == Kind.INT) { final double range = Math.abs(max - min); if (range == 0) { nrCaptions = 1; return; } // labeling for logarithmic scale if (log) { startvalue = min; nrCaptions = 3; return; } // labeling for linear scale final boolean dbl = type == Kind.DBL; actlCaptionStep = calculatedCaptionStep; nrCaptions = (int) (range / actlCaptionStep) + 1; while (2 * nrCaptions * PlotView.CAPTIONWHITESPACE * 3 < space && (dbl || actlCaptionStep % 2 == 0)) { actlCaptionStep /= 2; nrCaptions = (int) (range / actlCaptionStep); } while (nrCaptions * PlotView.CAPTIONWHITESPACE * 3 > space) { actlCaptionStep *= 2; nrCaptions = (int) (range / actlCaptionStep); } // calculate first value to be drawn startvalue = min + actlCaptionStep - min % actlCaptionStep; if (startvalue - min < actlCaptionStep / 4) startvalue += actlCaptionStep; // type == TEXT / CAT } else { nrCaptions = space / (PlotView.CAPTIONWHITESPACE * 3); if (nrCaptions > nrCats) nrCaptions = nrCats; actlCaptionStep = 1.0d / (nrCaptions - 1); } }
/** * Builds full-text information. * * @param d data reference * @param p pre value * @param str string value * @return number of added nodes */ TokenList build(final Data d, final int p, final byte[] str) { final FTPos ftp = ftpos.get(d, p); if (ftp == null) return null; boolean marked = false; final TokenList tl = new TokenList(); final TokenBuilder tb = new TokenBuilder(); final FTLexer lex = new FTLexer().sc().init(str); int len = -ftlen; while (lex.hasNext()) { final FTSpan span = lex.next(); // check if current text is still to be marked or already marked if (ftp.contains(span.pos) || marked) { if (tb.size() != 0) { // write current text node tl.add(tb.finish()); len += tb.size(); tb.reset(); // skip construction if (len >= 0 && tl.size() > 1 && !marked) break; } if (!marked) tl.add((byte[]) null); marked ^= true; } // add span tb.add(span.text); } // write last text node if (tb.size() != 0) { tl.add(tb.finish()); len += tb.size(); } // chop first and last text if (len > 0) { final int ts = tl.size(); // get first text (empty if it is a full-text match) final byte[] first = tl.get(0) != null ? tl.get(0) : EMPTY; // get last text (empty if it is a full-text match) final byte[] last = tl.get(ts - 2) != null ? tl.get(ts - 1) : EMPTY; if (first != EMPTY) { // remove leading characters of first text final double l = first.length + last.length; final int ll = Math.min(first.length, (int) (first.length / l * len)); tl.set(0, concat(DOTS, subtoken(first, ll))); len -= ll; } if (last != EMPTY && len > 0) { // remove trailing characters of last text final int ll = Math.min(last.length, len); tl.set(ts - 1, concat(subtoken(last, 0, last.length - ll), DOTS)); len -= ll; } // still too much text: shorten inner texts for (int t = ts - 2; t > 0 && len > 0; t--) { final byte[] txt = tl.get(t); // skip elements, marked texts and too short text snippets if (txt == null || tl.get(t - 1) == null) continue; final int ll = Math.min(txt.length, len); tl.set( t, concat( subtoken(txt, 0, (txt.length - ll) / 2), DOTS, subtoken(txt, (txt.length + ll) / 2))); len -= ll; } } return tl; }
/** * Returns the remaining, unscanned query substring. * * @return query substring */ protected final String rest() { final int ie = Math.min(length, pos + 15); return input.substring(pos, ie) + (ie == length ? "" : DOTS); }
/** * Parses the specified test case. * * @param root root node * @throws Exception exception * @return true if the query, specified by {@link #single}, was evaluated */ private boolean parse(final Nodes root) throws Exception { final String pth = text("@FilePath", root); final String outname = text("@name", root); if (single != null && !outname.startsWith(single)) return true; final Performance perf = new Performance(); if (verbose) Util.out("- " + outname); boolean inspect = false; boolean correct = true; final Nodes nodes = states(root); for (int n = 0; n < nodes.size(); ++n) { final Nodes state = new Nodes(nodes.list[n], nodes.data); final String inname = text("*:query/@name", state); context.query = new IOFile(queries + pth + inname + IO.XQSUFFIX); final String in = read(context.query); String er = null; ItemCache iter = null; boolean doc = true; final Nodes cont = nodes("*:contextItem", state); Nodes curr = null; if (cont.size() != 0) { final Data d = Check.check(context, srcs.get(string(data.atom(cont.list[0])))); curr = new Nodes(d.doc(), d); curr.root = true; } context.prop.set(Prop.QUERYINFO, compile); final QueryProcessor xq = new QueryProcessor(in, curr, context); context.prop.set(Prop.QUERYINFO, false); // limit result sizes to 1MB final ArrayOutput ao = new ArrayOutput(); final TokenBuilder files = new TokenBuilder(); try { files.add( file(nodes("*:input-file", state), nodes("*:input-file/@variable", state), xq, n == 0)); files.add(file(nodes("*:defaultCollection", state), null, xq, n == 0)); var(nodes("*:input-URI", state), nodes("*:input-URI/@variable", state), xq); eval(nodes("*:input-query/@name", state), nodes("*:input-query/@variable", state), pth, xq); parse(xq, state); for (final int p : nodes("*:module", root).list) { final String uri = text("@namespace", new Nodes(p, data)); final String file = mods.get(string(data.atom(p))) + IO.XQSUFFIX; xq.module(file, uri); } // evaluate and serialize query final SerializerProp sp = new SerializerProp(); sp.set(SerializerProp.S_INDENT, context.prop.is(Prop.CHOP) ? DataText.YES : DataText.NO); final XMLSerializer xml = new XMLSerializer(ao, sp); iter = xq.value().cache(); for (Item it; (it = iter.next()) != null; ) { doc &= it.type == NodeType.DOC; it.serialize(xml); } xml.close(); } catch (final Exception ex) { if (!(ex instanceof QueryException || ex instanceof IOException)) { System.err.println("\n*** " + outname + " ***"); System.err.println(in + "\n"); ex.printStackTrace(); } er = ex.getMessage(); if (er.startsWith(STOPPED)) er = er.substring(er.indexOf('\n') + 1); if (er.startsWith("[")) er = er.replaceAll("\\[(.*?)\\] (.*)", "$1 $2"); // unexpected error - dump stack trace } // print compilation steps if (compile) { Util.errln("---------------------------------------------------------"); Util.err(xq.info()); Util.errln(in); } final Nodes expOut = nodes("*:output-file/text()", state); final TokenList result = new TokenList(); for (int o = 0; o < expOut.size(); ++o) { final String resFile = string(data.atom(expOut.list[o])); final IOFile exp = new IOFile(expected + pth + resFile); result.add(read(exp)); } final Nodes cmpFiles = nodes("*:output-file/@compare", state); boolean xml = false; boolean frag = false; boolean ignore = false; for (int o = 0; o < cmpFiles.size(); ++o) { final byte[] type = data.atom(cmpFiles.list[o]); xml |= eq(type, XML); frag |= eq(type, FRAGMENT); ignore |= eq(type, IGNORE); } String expError = text("*:expected-error/text()", state); final StringBuilder log = new StringBuilder(pth + inname + IO.XQSUFFIX); if (files.size() != 0) { log.append(" ["); log.append(files); log.append("]"); } log.append(NL); /** Remove comments. */ log.append(norm(in)); log.append(NL); final String logStr = log.toString(); // skip queries with variable results final boolean print = currTime || !logStr.contains("current-"); boolean correctError = false; if (er != null && (expOut.size() == 0 || !expError.isEmpty())) { expError = error(pth + outname, expError); final String code = er.substring(0, Math.min(8, er.length())); for (final String e : SLASH.split(expError)) { if (code.equals(e)) { correctError = true; break; } } } if (correctError) { if (print) { logOK.append(logStr); logOK.append("[Right] "); logOK.append(norm(er)); logOK.append(NL); logOK.append(NL); addLog(pth, outname + ".log", er); } ++ok; } else if (er == null) { int s = -1; final int rs = result.size(); while (!ignore && ++s < rs) { inspect |= s < cmpFiles.list.length && eq(data.atom(cmpFiles.list[s]), INSPECT); final byte[] res = result.get(s), actual = ao.toArray(); if (res.length == ao.size() && eq(res, actual)) break; if (xml || frag) { iter.reset(); try { final ItemCache ic = toIter(string(res).replaceAll("^<\\?xml.*?\\?>", "").trim(), frag); if (FNSimple.deep(null, iter, ic)) break; ic.reset(); final ItemCache ia = toIter(string(actual), frag); if (FNSimple.deep(null, ia, ic)) break; } catch (final Throwable ex) { System.err.println("\n" + outname + ":"); ex.printStackTrace(); } } } if ((rs > 0 || !expError.isEmpty()) && s == rs && !inspect) { if (print) { if (expOut.size() == 0) result.add(error(pth + outname, expError)); logErr.append(logStr); logErr.append("[" + testid + " ] "); logErr.append(norm(string(result.get(0)))); logErr.append(NL); logErr.append("[Wrong] "); logErr.append(norm(ao.toString())); logErr.append(NL); logErr.append(NL); addLog(pth, outname + (xml ? IO.XMLSUFFIX : ".txt"), ao.toString()); } correct = false; ++err; } else { if (print) { logOK.append(logStr); logOK.append("[Right] "); logOK.append(norm(ao.toString())); logOK.append(NL); logOK.append(NL); addLog(pth, outname + (xml ? IO.XMLSUFFIX : ".txt"), ao.toString()); } ++ok; } } else { if (expOut.size() == 0 || !expError.isEmpty()) { if (print) { logOK2.append(logStr); logOK2.append("[" + testid + " ] "); logOK2.append(norm(expError)); logOK2.append(NL); logOK2.append("[Rght?] "); logOK2.append(norm(er)); logOK2.append(NL); logOK2.append(NL); addLog(pth, outname + ".log", er); } ++ok2; } else { if (print) { logErr2.append(logStr); logErr2.append("[" + testid + " ] "); logErr2.append(norm(string(result.get(0)))); logErr2.append(NL); logErr2.append("[Wrong] "); logErr2.append(norm(er)); logErr2.append(NL); logErr2.append(NL); addLog(pth, outname + ".log", er); } correct = false; ++err2; } } if (curr != null) Close.close(curr.data, context); xq.close(); } if (reporting) { logReport.append(" <test-case name=\""); logReport.append(outname); logReport.append("\" result='"); logReport.append(correct ? "pass" : "fail"); if (inspect) logReport.append("' todo='inspect"); logReport.append("'/>"); logReport.append(NL); } // print verbose/timing information final long nano = perf.getTime(); final boolean slow = nano / 1000000 > timer; if (verbose) { if (slow) Util.out(": " + Performance.getTimer(nano, 1)); Util.outln(); } else if (slow) { Util.out(NL + "- " + outname + ": " + Performance.getTimer(nano, 1)); } return single == null || !outname.equals(single); }
/** * Analyzes the specified patterns. * * @param patterns patterns * @return picture variables */ private Picture[] analyze(final byte[][] patterns) { // pictures final int picL = patterns.length; final Picture[] pics = new Picture[picL]; // analyze patterns for (int p = 0; p < picL; p++) { final byte[] pt = patterns[p]; final Picture pic = new Picture(); // position (integer/fractional) int pos = 0; // active character found boolean act = false; // number of characters after exponent int exp = -1; // number of optional characters final int[] opt = new int[2]; // loop through all characters final int pl = pt.length; for (int i = 0, cl; i < pl; i += cl) { final int ch = ch(pt, i); cl = cl(pt, i); boolean active = contains(actives, ch); if (ch == decimal) { ++pos; act = false; } else if (ch == optional) { opt[pos]++; } else if (ch == exponent) { if (act && containsActive(pt, i + cl)) { exp = 0; } else { active = false; } } else if (ch == grouping) { if (pos == 0) pic.group[pos] = Array.add(pic.group[pos], pic.min[pos] + opt[pos]); } else if (contains(digits, ch)) { if (exp == -1) pic.min[pos]++; else exp++; } if (active) { act = true; } else { // passive characters pic.pc |= ch == percent; pic.pm |= ch == permille; // prefixes/suffixes pic.prefSuf[pos == 0 && act ? pos + 1 : pos].add(ch); } } // finalize integer-part-grouping-positions final int[] igp = pic.group[0]; final int igl = igp.length; for (int g = 0; g < igl; ++g) igp[g] = pic.min[0] + opt[0] - igp[g]; // check if integer-part-grouping-positions are regular // if yes, they are replaced with a single position if (igl > 1) { boolean reg = true; final int i = igp[igl - 1]; for (int g = igl - 2; g >= 0; --g) reg &= i * igl == igp[g]; if (reg) pic.group[0] = new int[] {i}; } pic.maxFrac = pic.min[1] + opt[1]; pic.minExp = Math.max(0, exp); pics[p] = pic; } return pics; }
/** Executes some calculations to support a dynamic axis labeling for a linear scale. */ private void prepareLinAxis() { // range as driving force for following calculations, no matter if INT // or DBL ... whatsoever double range = Math.abs(max - min); if (range == 0) return; // small ranges between min and max value if (range < 1) { final double dec = 1.0d / range; double pow = (int) (Math.floor(Math.log10(dec) + .5d) + 1) * 2; final double fac = (int) Math.pow(10, pow); final double tmin = min * fac; final double tmax = max * fac; range = Math.abs(tmax - tmin); pow = range < 10 ? 0 : (int) Math.floor(Math.log10(range) + .5d) - 1; calculatedCaptionStep = (int) Math.pow(10, pow); calculatedCaptionStep /= fac; return; } final int pow = range < 10 ? 0 : (int) Math.floor(Math.log10(range) + .5d) - 1; calculatedCaptionStep = (int) Math.pow(10, pow); }
/** * Sets an element at the specified index. * * @param i index * @param e element to be set */ public void set(final int i, final byte[] e) { if (i >= list.length) list = Array.copyOf(list, newSize(i + 1)); list[i] = e; size = Math.max(size, i + 1); }
/** * Formats the specified number and returns a string representation. * * @param item item * @param pics pictures * @param ii input info * @return picture variables * @throws QueryException query exception */ private byte[] format(final ANum item, final Picture[] pics, final InputInfo ii) throws QueryException { // Rule 1: return results for NaN final double d = item.dbl(ii); if (Double.isNaN(d)) return nan; // Rule 2: check if value if negative (smaller than zero or -0) final boolean neg = d < 0 || d == 0 && Double.doubleToLongBits(d) == Long.MIN_VALUE; final Picture pic = pics[neg && pics.length == 2 ? 1 : 0]; final IntList res = new IntList(), intgr = new IntList(), fract = new IntList(); int exp = 0; // Rule 3: percent/permille ANum num = item; if (pic.pc) num = (ANum) Calc.MULT.ev(num, Int.get(100), ii); if (pic.pm) num = (ANum) Calc.MULT.ev(num, Int.get(1000), ii); if (Double.isInfinite(num.dbl(ii))) { // Rule 4: infinity intgr.add(new TokenParser(inf).toArray()); } else { // Rule 5: exponent if (pic.minExp != 0 && d != 0) { BigDecimal dec = num.dec(ii).abs().stripTrailingZeros(); int scl = 0; if (dec.compareTo(BigDecimal.ONE) >= 0) { scl = dec.setScale(0, RoundingMode.HALF_DOWN).precision(); } else { while (dec.compareTo(BigDecimal.ONE) < 0) { dec = dec.multiply(BigDecimal.TEN); scl--; } scl++; } exp = scl - pic.min[0]; if (exp != 0) { final BigDecimal n = BigDecimal.TEN.pow(Math.abs(exp)); num = (ANum) Calc.MULT.ev(num, Dec.get(exp > 0 ? BigDecimal.ONE.divide(n) : n), ii); } } num = num.round(pic.maxFrac, true).abs(); // convert positive number to string final String s = (num instanceof Dbl || num instanceof Flt ? Dec.get(BigDecimal.valueOf(num.dbl(ii))) : num) .toString(); // integer/fractional separator final int sep = s.indexOf('.'); // create integer part final int sl = s.length(); final int il = sep == -1 ? sl : sep; for (int i = il; i < pic.min[0]; ++i) intgr.add(zero); // fractional number: skip leading 0 if (!s.startsWith("0.") || pic.min[0] > 0) { for (int i = 0; i < il; i++) intgr.add(zero + s.charAt(i) - '0'); } // squeeze in grouping separators if (pic.group[0].length == 1 && pic.group[0][0] > 0) { // regular pattern with repeating separators for (int p = intgr.size() - (neg ? 2 : 1); p > 0; --p) { if (p % pic.group[0][0] == 0) intgr.insert(intgr.size() - p, grouping); } } else { // irregular pattern, or no separators at all final int gl = pic.group[0].length; for (int g = 0; g < gl; ++g) { final int pos = intgr.size() - pic.group[0][g]; if (pos > 0) intgr.insert(pos, grouping); } } // create fractional part final int fl = sep == -1 ? 0 : sl - il - 1; if (fl != 0) for (int i = sep + 1; i < sl; i++) fract.add(zero + s.charAt(i) - '0'); for (int i = fl; i < pic.min[1]; ++i) fract.add(zero); // squeeze in grouping separators in a reverse manner final int ul = fract.size(); for (int p = pic.group[1].length - 1; p >= 0; p--) { final int pos = pic.group[1][p]; if (pos < ul) fract.insert(pos, grouping); } } // add minus sign if (neg && pics.length != 2) res.add(minus); // add prefix and integer part res.add(pic.prefSuf[0].toArray()).add(intgr.finish()); // add fractional part if (!fract.isEmpty()) res.add(decimal).add(fract.finish()); // add exponent if (pic.minExp != 0) { res.add(exponent); if (exp < 0) res.add(minus); final String s = Integer.toString(Math.abs(exp)); final int sl = s.length(); for (int i = sl; i < pic.minExp; i++) res.add(zero); for (int i = 0; i < sl; i++) res.add(zero + s.charAt(i) - '0'); } // add suffix res.add(pic.prefSuf[1].toArray()); return new TokenBuilder(res.finish()).finish(); }
/** * Inserts a data instance at the specified pre value. Note that the specified data instance must * differ from this instance. * * @param ipre value at which to insert new data * @param ipar parent pre value of node * @param clip data clip */ public final void insert(final int ipre, final int ipar, final DataClip clip) { meta.update(); // update value and document indexes if (meta.updindex) indexBegin(); resources.insert(ipre, clip); final int dsize = clip.size(); final int buf = Math.min(dsize, IO.BLOCKSIZE >> IO.NODEPOWER); // resize buffer to cache more entries buffer(buf); // find all namespaces in scope to avoid duplicate declarations final TokenMap nsScope = nspaces.scope(ipar, this); // loop through all entries final IntList preStack = new IntList(); final NSNode nsRoot = nspaces.current(); final HashSet<NSNode> newNodes = new HashSet<NSNode>(); final IntList flagPres = new IntList(); // indicates if database only contains a dummy node final Data data = clip.data; int c = 0; for (int dpre = clip.start; dpre < clip.end; ++dpre, ++c) { if (c != 0 && c % buf == 0) insert(ipre + c - buf); final int pre = ipre + c; final int dkind = data.kind(dpre); final int dpar = data.parent(dpre, dkind); // ipar < 0 if document nodes on top level are added final int dis = dpar >= 0 ? dpre - dpar : ipar >= 0 ? pre - ipar : 0; final int par = dis == 0 ? -1 : pre - dis; if (c == 0) nspaces.root(par, this); while (!preStack.isEmpty() && preStack.peek() > par) nspaces.close(preStack.pop()); switch (dkind) { case DOC: // add document nspaces.prepare(); final int s = data.size(dpre, dkind); doc(pre, s, data.text(dpre, true)); meta.ndocs++; preStack.push(pre); break; case ELEM: // add element nspaces.prepare(); boolean ne = false; if (data.nsFlag(dpre)) { final Atts at = data.ns(dpre); for (int a = 0; a < at.size(); ++a) { // see if prefix has been declared/ is part of current ns scope final byte[] old = nsScope.get(at.name(a)); if (old == null || !eq(old, at.value(a))) { // we have to keep track of all new NSNodes that are added // to the Namespace structure, as their pre values must not // be updated. I.e. if an NSNode N with pre value 3 existed // prior to inserting and two new nodes are inserted at // location pre == 3 we have to make sure N and only N gets // updated. newNodes.add(nspaces.add(at.name(a), at.value(a), pre)); ne = true; } } } byte[] nm = data.name(dpre, dkind); elem( dis, tagindex.index(nm, null, false), data.attSize(dpre, dkind), data.size(dpre, dkind), nspaces.uri(nm, true), ne); preStack.push(pre); break; case TEXT: case COMM: case PI: // add text text(pre, dis, data.text(dpre, true), dkind); break; case ATTR: // add attribute nm = data.name(dpre, dkind); // check if prefix already in nsScope or not final byte[] attPref = prefix(nm); // check if prefix of attribute has already been declared, otherwise // add declaration to parent node if (data.nsFlag(dpre) && nsScope.get(attPref) == null) { nspaces.add( par, preStack.isEmpty() ? -1 : preStack.peek(), attPref, data.nspaces.uri(data.uri(dpre, dkind)), this); // save pre value to set ns flag later for this node. can't be done // here as direct table access would interfere with the buffer flagPres.add(par); } attr( pre, dis, atnindex.index(nm, null, false), data.text(dpre, false), nspaces.uri(nm, false), false); break; } } // finalize and update namespace structure while (!preStack.isEmpty()) nspaces.close(preStack.pop()); nspaces.root(nsRoot); if (bp != 0) insert(ipre + c - 1 - (c - 1) % buf); // reset buffer to old size buffer(1); // set ns flags for (int f = 0; f < flagPres.size(); f++) { final int fl = flagPres.get(f); table.write2(fl, 1, name(fl) | 1 << 15); } // increase size of ancestors int p = ipar; while (p >= 0) { final int k = kind(p); size(p, k, size(p, k) + dsize); p = parent(p, k); } if (meta.updindex) { // add the entries to the ID -> PRE mapping: idmap.insert(ipre, id(ipre), dsize); indexEnd(); } if (!cache) updateDist(ipre + dsize, dsize); // propagate PRE value shifts to namespaces if (ipar != -1) nspaces.insert(ipre, dsize, newNodes); }
/** * Calculates base e logarithm for the given value. * * @param d value * @return base e logarithm for d */ private double ln(final double d) { return d == 0 ? 0 : Math.log1p(Math.abs(d)); }