List of usage examples for java.util Stack empty
public boolean empty()
From source file:org.apache.tajo.plan.LogicalPlanner.java
public LogicalNode postHook(PlanContext context, Stack<Expr> stack, Expr expr, LogicalNode current) throws TajoException { // Some generated logical nodes (e.g., implicit aggregation) without exprs will pass NULL as a expr parameter. // We should skip them. if (expr != null) { // A relation list including a single ScanNode will return a ScanNode instance that already passed postHook. // So, it skips the already-visited ScanNode instance. if (expr.getType() == OpType.RelationList && current.getType() == NodeType.SCAN) { return current; }/*from w w w . j av a 2s.c o m*/ } QueryBlock queryBlock = context.queryBlock; queryBlock.updateLatestNode(current); // if this node is the topmost if (stack.size() == 0) { queryBlock.setRoot(current); } if (!stack.empty()) { queryBlock.updateCurrentNode(stack.peek()); } return current; }
From source file:org.xlrnet.tibaija.processor.FullTIBasicVisitor.java
private int internalHandleSkipFlowLogic(int currentCommandCounter, List<TIBasicParser.CommandContext> commandList, Stack<ControlFlowElement.ControlFlowToken> skipCommandsStack, TIBasicParser.CommandContext nextCommand) { int commandListSize = commandList.size(); final String enumName = nextCommand.controlFlowStatement().flowType; ControlFlowElement.ControlFlowToken currentFlowToken = EnumUtils .getEnum(ControlFlowElement.ControlFlowToken.class, enumName); ControlFlowElement.ControlFlowToken topToken = skipCommandsStack.peek(); if (currentFlowToken == null) { throw new IllegalStateException( "Internal error: control flow token is null at command " + currentCommandCounter); }//from w w w . j ava 2s. c o m switch (currentFlowToken) { case IF: // Look ahead if the next command might be a "Then" i.e. if it is a controlflow statement if (commandListSize <= currentCommandCounter + 1) { throw new IllegalControlFlowException(-1, -1, "Illegal 'If' at the end of the program"); } else if (commandList.get(currentCommandCounter + 1).isControlFlowStatement) { skipCommandsStack.push(currentFlowToken); LOGGER.debug("Predicted multiline IF while skipping over command {}", currentCommandCounter); } else { LOGGER.debug("Skipping over single line IF at command {}", currentCommandCounter); currentCommandCounter++; } break; case THEN: if (topToken != ControlFlowElement.ControlFlowToken.IF) throw new IllegalControlFlowException(-1, -1, "Illegal 'Then' Statement without preceding 'If'"); skipCommandsStack.pop(); skipCommandsStack.push(currentFlowToken); break; case ELSE: if (skipCommandsStack.size() > 1 && topToken != ControlFlowElement.ControlFlowToken.THEN) throw new IllegalControlFlowException(-1, -1, "Illegal 'Else' Statement without preceding 'Then' "); skipCommandsStack.pop(); if (!skipCommandsStack.empty()) skipCommandsStack.push(topToken); break; case FOR: case WHILE: case REPEAT: skipCommandsStack.push(currentFlowToken); break; case END: skipCommandsStack.pop(); break; case GOTO: case LABEL: break; default: throw new IllegalStateException("Illegal flow token: " + currentFlowToken); } if (skipCommandsStack.empty()) { LOGGER.debug("Skip stack is now empty - continuing execution at command {}", currentCommandCounter + 1); } return currentCommandCounter; }
From source file:org.apache.tajo.engine.planner.rewrite.ProjectionPushDownRule.java
@Override public LogicalNode visitProjection(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, ProjectionNode node, Stack<LogicalNode> stack) throws PlanningException { Context newContext = new Context(context); Target[] targets = node.getTargets(); int targetNum = targets.length; String[] referenceNames = new String[targetNum]; for (int i = 0; i < targetNum; i++) { referenceNames[i] = newContext.addExpr(targets[i]); }/* www . ja v a 2 s .co m*/ LogicalNode child = super.visitProjection(newContext, plan, block, node, stack); node.setInSchema(child.getOutSchema()); int evaluationCount = 0; List<Target> finalTargets = TUtil.newList(); for (String referenceName : referenceNames) { Target target = context.targetListMgr.getTarget(referenceName); if (target.getEvalTree().getType() == EvalType.CONST) { finalTargets.add(target); } else if (context.targetListMgr.isEvaluated(referenceName)) { if (context.targetListMgr.isNativeAlias(referenceName)) { String realRefName = context.targetListMgr.getRealReferenceName(referenceName); finalTargets.add(new Target(new FieldEval(realRefName, target.getDataType()), referenceName)); } else { finalTargets.add(new Target(new FieldEval(target.getNamedColumn()))); } } else if (LogicalPlanner.checkIfBeEvaluatedAtThis(target.getEvalTree(), node)) { finalTargets.add(target); context.targetListMgr.markAsEvaluated(target); evaluationCount++; } } node.setTargets(finalTargets.toArray(new Target[finalTargets.size()])); LogicalPlanner.verifyProjectedFields(block, node); // Removing ProjectionNode // TODO - Consider INSERT and CTAS statement, and then remove the check of stack.empty. if (evaluationCount == 0 && PlannerUtil.targetToSchema(finalTargets).equals(child.getOutSchema())) { if (stack.empty()) { // if it is topmost, set it as the root of this block. block.setRoot(child); } else { LogicalNode parentNode = stack.peek(); switch (parentNode.getType()) { case ROOT: LogicalRootNode rootNode = (LogicalRootNode) parentNode; rootNode.setChild(child); rootNode.setInSchema(child.getOutSchema()); rootNode.setOutSchema(child.getOutSchema()); break; case TABLE_SUBQUERY: TableSubQueryNode tableSubQueryNode = (TableSubQueryNode) parentNode; tableSubQueryNode.setSubQuery(child); break; case STORE: StoreTableNode storeTableNode = (StoreTableNode) parentNode; storeTableNode.setChild(child); storeTableNode.setInSchema(child.getOutSchema()); break; case INSERT: InsertNode insertNode = (InsertNode) parentNode; insertNode.setSubQuery(child); break; case CREATE_TABLE: CreateTableNode createTableNode = (CreateTableNode) parentNode; createTableNode.setChild(child); createTableNode.setInSchema(child.getOutSchema()); break; default: throw new PlanningException("Unexpected Parent Node: " + parentNode.getType()); } plan.addHistory("ProjectionNode is eliminated."); } return child; } else { return node; } }
From source file:org.apache.tajo.plan.rewrite.rules.ProjectionPushDownRule.java
@Override public LogicalNode visitProjection(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, ProjectionNode node, Stack<LogicalNode> stack) throws TajoException { Context newContext = new Context(context); List<Target> targets = node.getTargets(); int targetNum = targets.size(); String[] referenceNames = new String[targetNum]; for (int i = 0; i < targetNum; i++) { referenceNames[i] = newContext.addExpr(targets.get(i)); }// ww w .j a v a 2s. c om LogicalNode child = super.visitProjection(newContext, plan, block, node, stack); node.setInSchema(child.getOutSchema()); int evaluationCount = 0; List<Target> finalTargets = new ArrayList<>(); for (String referenceName : referenceNames) { Target target = context.targetListMgr.getTarget(referenceName); if (target.getEvalTree().getType() == EvalType.CONST) { finalTargets.add(target); } else if (context.targetListMgr.isEvaluated(referenceName)) { if (context.targetListMgr.isNativeAlias(referenceName)) { String realRefName = context.targetListMgr.getRealReferenceName(referenceName); finalTargets.add(new Target(new FieldEval(realRefName, target.getDataType()), referenceName)); } else { finalTargets.add(new Target(new FieldEval(target.getNamedColumn()))); } } else if (LogicalPlanner.checkIfBeEvaluatedAtThis(target.getEvalTree(), node)) { finalTargets.add(target); context.targetListMgr.markAsEvaluated(target); evaluationCount++; } } node.setTargets(finalTargets); LogicalPlanner.verifyProjectedFields(block, node); // Removing ProjectionNode // TODO - Consider INSERT and CTAS statement, and then remove the check of stack.empty. if (evaluationCount == 0 && PlannerUtil.targetToSchema(finalTargets).equals(child.getOutSchema())) { if (stack.empty()) { // if it is topmost, set it as the root of this block. block.setRoot(child); } else { LogicalNode parentNode = stack.peek(); switch (parentNode.getType()) { case ROOT: LogicalRootNode rootNode = (LogicalRootNode) parentNode; rootNode.setChild(child); rootNode.setInSchema(child.getOutSchema()); rootNode.setOutSchema(child.getOutSchema()); break; case TABLE_SUBQUERY: TableSubQueryNode tableSubQueryNode = (TableSubQueryNode) parentNode; tableSubQueryNode.setSubQuery(child); break; case STORE: StoreTableNode storeTableNode = (StoreTableNode) parentNode; storeTableNode.setChild(child); storeTableNode.setInSchema(child.getOutSchema()); break; case INSERT: InsertNode insertNode = (InsertNode) parentNode; insertNode.setSubQuery(child); break; case CREATE_TABLE: CreateTableNode createTableNode = (CreateTableNode) parentNode; createTableNode.setChild(child); createTableNode.setInSchema(child.getOutSchema()); break; case CREATE_INDEX: CreateIndexNode createIndexNode = (CreateIndexNode) parentNode; createIndexNode.setChild(child); createIndexNode.setInSchema(child.getOutSchema()); break; default: throw new TajoInternalError("unexpected parent node: " + parentNode.getType()); } plan.addHistory("ProjectionNode is eliminated."); } return child; } else { return node; } }
From source file:org.trnltk.experiment.morphology.ambiguity.DataDiffUtil.java
/** * Reduce the number of edits by eliminating semantically trivial equalities. * * @param diffs LinkedList of Diff objects. *//*w ww .ja v a2s . c om*/ public void diff_cleanupSemantic(LinkedList<Diff<T>> diffs) { if (diffs.isEmpty()) { return; } boolean changes = false; Stack<Diff<T>> equalities = new Stack<Diff<T>>(); // Stack of qualities. List<T> lastequality = null; // Always equal to equalities.lastElement().text ListIterator<Diff<T>> pointer = diffs.listIterator(); // Number of characters that changed prior to the equality. int length_insertions1 = 0; int length_deletions1 = 0; // Number of characters that changed after the equality. int length_insertions2 = 0; int length_deletions2 = 0; Diff<T> thisDiff = pointer.next(); while (thisDiff != null) { if (thisDiff.operation == Operation.EQUAL) { // Equality found. equalities.push(thisDiff); length_insertions1 = length_insertions2; length_deletions1 = length_deletions2; length_insertions2 = 0; length_deletions2 = 0; lastequality = thisDiff.text; } else { // An insertion or deletion. if (thisDiff.operation == Operation.INSERT) { length_insertions2 += thisDiff.text.size(); } else { length_deletions2 += thisDiff.text.size(); } // Eliminate an equality that is smaller or equal to the edits on both // sides of it. if (lastequality != null && (lastequality.size() <= Math.max(length_insertions1, length_deletions1)) && (lastequality.size() <= Math.max(length_insertions2, length_deletions2))) { //System.out.println("Splitting: '" + lastequality + "'"); // Walk back to offending equality. while (thisDiff != equalities.lastElement()) { thisDiff = pointer.previous(); } pointer.next(); // Replace equality with a delete. pointer.set(new Diff(Operation.DELETE, lastequality)); // Insert a corresponding an insert. pointer.add(new Diff(Operation.INSERT, lastequality)); equalities.pop(); // Throw away the equality we just deleted. if (!equalities.empty()) { // Throw away the previous equality (it needs to be reevaluated). equalities.pop(); } if (equalities.empty()) { // There are no previous equalities, walk back to the start. while (pointer.hasPrevious()) { pointer.previous(); } } else { // There is a safe equality we can fall back to. thisDiff = equalities.lastElement(); while (thisDiff != pointer.previous()) { // Intentionally empty loop. } } length_insertions1 = 0; // Reset the counters. length_insertions2 = 0; length_deletions1 = 0; length_deletions2 = 0; lastequality = null; changes = true; } } thisDiff = pointer.hasNext() ? pointer.next() : null; } // Normalize the diff. if (changes) { diff_cleanupMerge(diffs); } diff_cleanupSemanticLossless(diffs); // Find any overlaps between deletions and insertions. // e.g: <del>abcxxx</del><ins>xxxdef</ins> // -> <del>abc</del>xxx<ins>def</ins> // e.g: <del>xxxabc</del><ins>defxxx</ins> // -> <ins>def</ins>xxx<del>abc</del> // Only extract an overlap if it is as big as the edit ahead or behind it. pointer = diffs.listIterator(); Diff<T> prevDiff = null; thisDiff = null; if (pointer.hasNext()) { prevDiff = pointer.next(); if (pointer.hasNext()) { thisDiff = pointer.next(); } } while (thisDiff != null) { if (prevDiff.operation == Operation.DELETE && thisDiff.operation == Operation.INSERT) { List<T> deletion = prevDiff.text; List<T> insertion = thisDiff.text; int overlap_length1 = this.diff_commonOverlap(deletion, insertion); int overlap_length2 = this.diff_commonOverlap(insertion, deletion); if (overlap_length1 >= overlap_length2) { if (overlap_length1 >= deletion.size() / 2.0 || overlap_length1 >= insertion.size() / 2.0) { // Overlap found. Insert an equality and trim the surrounding edits. pointer.previous(); pointer.add(new Diff<T>(Operation.EQUAL, insertion.subList(0, overlap_length1))); prevDiff.text = deletion.subList(0, deletion.size() - overlap_length1); thisDiff.text = insertion.subList(overlap_length1, insertion.size()); // pointer.add inserts the element before the cursor, so there is // no need to step past the new element. } } else { if (overlap_length2 >= deletion.size() / 2.0 || overlap_length2 >= insertion.size() / 2.0) { // Reverse overlap found. // Insert an equality and swap and trim the surrounding edits. pointer.previous(); pointer.add(new Diff<T>(Operation.EQUAL, deletion.subList(0, overlap_length2))); prevDiff.operation = Operation.INSERT; prevDiff.text = insertion.subList(0, insertion.size() - overlap_length2); thisDiff.operation = Operation.DELETE; thisDiff.text = deletion.subList(overlap_length2, deletion.size()); // pointer.add inserts the element before the cursor, so there is // no need to step past the new element. } } thisDiff = pointer.hasNext() ? pointer.next() : null; } prevDiff = thisDiff; thisDiff = pointer.hasNext() ? pointer.next() : null; } }
From source file:alluxio.master.file.DefaultFileSystemMaster.java
/** * Implements renaming.//from w w w . ja va 2s. c o m * * @param srcInodePath the path of the rename source * @param dstInodePath the path to the rename destination * @param replayed whether the operation is a result of replaying the journal * @param options method options * @throws FileDoesNotExistException if a non-existent file is encountered * @throws InvalidPathException if an invalid path is encountered * @throws IOException if an I/O error is encountered */ private void renameInternal(LockedInodePath srcInodePath, LockedInodePath dstInodePath, boolean replayed, RenameOptions options) throws FileDoesNotExistException, InvalidPathException, IOException { // Rename logic: // 1. Change the source inode name to the destination name. // 2. Insert the source inode into the destination parent. // 3. Do UFS operations if necessary. // 4. Remove the source inode (reverting the name) from the source parent. // 5. Set the last modification times for both source and destination parent inodes. Inode<?> srcInode = srcInodePath.getInode(); AlluxioURI srcPath = srcInodePath.getUri(); AlluxioURI dstPath = dstInodePath.getUri(); InodeDirectory srcParentInode = srcInodePath.getParentInodeDirectory(); InodeDirectory dstParentInode = dstInodePath.getParentInodeDirectory(); String srcName = srcPath.getName(); String dstName = dstPath.getName(); LOG.debug("Renaming {} to {}", srcPath, dstPath); // 1. Change the source inode name to the destination name. srcInode.setName(dstName); srcInode.setParentId(dstParentInode.getId()); // 2. Insert the source inode into the destination parent. if (!dstParentInode.addChild(srcInode)) { // On failure, revert changes and throw exception. srcInode.setName(srcName); srcInode.setParentId(srcParentInode.getId()); throw new InvalidPathException("Destination path: " + dstPath + " already exists."); } // 3. Do UFS operations if necessary. // If the source file is persisted, rename it in the UFS. try { if (!replayed && srcInode.isPersisted()) { MountTable.Resolution resolution = mMountTable.resolve(srcPath); String ufsSrcPath = resolution.getUri().toString(); UnderFileSystem ufs = resolution.getUfs(); String ufsDstUri = mMountTable.resolve(dstPath).getUri().toString(); // Create ancestor directories from top to the bottom. We cannot use recursive create // parents here because the permission for the ancestors can be different. List<Inode<?>> dstInodeList = dstInodePath.getInodeList(); Stack<Pair<String, MkdirsOptions>> ufsDirsToMakeWithOptions = new Stack<>(); AlluxioURI curUfsDirPath = new AlluxioURI(ufsDstUri).getParent(); // The dst inode does not exist yet, so the last inode in the list is the existing parent. for (int i = dstInodeList.size() - 1; i >= 0; i--) { if (ufs.isDirectory(curUfsDirPath.toString())) { break; } Inode<?> curInode = dstInodeList.get(i); MkdirsOptions mkdirsOptions = MkdirsOptions.defaults().setCreateParent(false) .setOwner(curInode.getOwner()).setGroup(curInode.getGroup()) .setMode(new Mode(curInode.getMode())); ufsDirsToMakeWithOptions.push(new Pair<>(curUfsDirPath.toString(), mkdirsOptions)); curUfsDirPath = curUfsDirPath.getParent(); } while (!ufsDirsToMakeWithOptions.empty()) { Pair<String, MkdirsOptions> ufsDirAndPerm = ufsDirsToMakeWithOptions.pop(); if (!ufs.mkdirs(ufsDirAndPerm.getFirst(), ufsDirAndPerm.getSecond())) { throw new IOException( ExceptionMessage.FAILED_UFS_CREATE.getMessage(ufsDirAndPerm.getFirst())); } } boolean success; if (srcInode.isFile()) { success = ufs.renameFile(ufsSrcPath, ufsDstUri); } else { success = ufs.renameDirectory(ufsSrcPath, ufsDstUri); } if (!success) { throw new IOException(ExceptionMessage.FAILED_UFS_RENAME.getMessage(ufsSrcPath, ufsDstUri)); } } } catch (Exception e) { // On failure, revert changes and throw exception. if (!dstParentInode.removeChild(dstName)) { LOG.error("Failed to revert rename changes. Alluxio metadata may be inconsistent."); } srcInode.setName(srcName); srcInode.setParentId(srcParentInode.getId()); throw e; } // TODO(jiri): A crash between now and the time the rename operation is journaled will result in // an inconsistency between Alluxio and UFS. // 4. Remove the source inode (reverting the name) from the source parent. The name must be // reverted or removeChild will not be able to find the appropriate child entry since it is // keyed on the original name. srcInode.setName(srcName); if (!srcParentInode.removeChild(srcInode)) { // This should never happen. LOG.error("Failed to rename {} to {} in Alluxio. Alluxio and under storage may be " + "inconsistent.", srcPath, dstPath); srcInode.setName(dstName); if (!dstParentInode.removeChild(dstName)) { LOG.error("Failed to revert changes when renaming {} to {}. Alluxio metadata may be " + "inconsistent.", srcPath, dstPath); } srcInode.setName(srcName); srcInode.setParentId(srcParentInode.getId()); throw new IOException("Failed to remove source path " + srcPath + " from parent"); } srcInode.setName(dstName); // 5. Set the last modification times for both source and destination parent inodes. // Note this step relies on setLastModificationTimeMs being thread safe to guarantee the // correct behavior when multiple files are being renamed within a directory. dstParentInode.setLastModificationTimeMs(options.getOperationTimeMs()); srcParentInode.setLastModificationTimeMs(options.getOperationTimeMs()); Metrics.PATHS_RENAMED.inc(); }
From source file:com.almarsoft.GroundhogReader.MessageListActivity.java
private void fillListNonRecursive(Article root, int depth, String replyto) { Stack<MiniHeader> stack = new Stack<MiniHeader>(); boolean markReplies = mPrefs.getBoolean("markReplies", true); boolean finished = false; String clean_subject;//from w w w .j a v a 2s . c om MiniHeader tmpMiniItem; HeaderItemClass ih = null; String[] refsArray; String msgId; ArrayList<HeaderItemClass> nonStarredItems = new ArrayList<HeaderItemClass>(); HashSet<String> bannedTrollsSet = DBUtils.getBannedTrolls(getApplicationContext()); HashSet<String> starredSet = DBUtils.getStarredSubjectsSet(getApplicationContext()); // Proxy for speed HashSet<String> myPostsSetProxy = mMyPostsSet; ArrayList<HeaderItemClass> headerItemsListProxy = new ArrayList<HeaderItemClass>(); int refsArrayLen; while (!finished) { if (root == null) finished = true; root.setReplyTo(replyto); if (!root.isDummy()) { ih = new HeaderItemClass(root, depth); // Don't feed the troll if (!bannedTrollsSet.contains(root.getFrom())) { // Put the replies in red (if configured) if (markReplies) { refsArray = root.getReferences(); refsArrayLen = refsArray.length; msgId = null; if (refsArray != null && refsArrayLen > 0) { msgId = refsArray[refsArrayLen - 1]; } if (msgId != null && myPostsSetProxy != null && myPostsSetProxy.contains(msgId)) ih.myreply = true; else ih.myreply = false; } clean_subject = root.simplifiedSubject(); if (starredSet.contains(clean_subject)) { ih.starred = true; headerItemsListProxy.add(ih); // Starred items first } else { // Nonstarred items will be added to mHeaderItemsList at the end nonStarredItems.add(ih); } } } if (root.next != null) { tmpMiniItem = new MiniHeader(root.next, depth, replyto); stack.push(tmpMiniItem); } if (root.kid != null) { replyto = root.getFrom(); if (!root.isDummy()) ++depth; root = root.kid; } else if (!stack.empty()) { tmpMiniItem = stack.pop(); root = tmpMiniItem.article; depth = tmpMiniItem.depth; replyto = tmpMiniItem.replyto; } else finished = true; } // Now add the non starred items after the starred ones int nonStarredItemsLen = nonStarredItems.size(); for (int i = 0; i < nonStarredItemsLen; i++) { headerItemsListProxy.add(nonStarredItems.get(i)); } mHeaderItemsList = headerItemsListProxy; nonStarredItems = null; }
From source file:org.sakaiproject.content.tool.ListItem.java
/** * @param item//from www . j av a 2s . c o m * @return */ public List<ListItem> convert2list() { List<ListItem> list = new ArrayList<ListItem>(); Stack<ListItem> processStack = new Stack<ListItem>(); processStack.push(this); while (!processStack.empty()) { ListItem parent = processStack.pop(); list.add(parent); List<ListItem> children = parent.getMembers(); if (children != null) { for (int i = children.size() - 1; i >= 0; i--) { ListItem child = children.get(i); processStack.push(child); } } } return list; }
From source file:org.wso2.ballerinalang.compiler.parser.BLangPackageBuilder.java
private List<BLangExpression> getExpressionsInTemplate(DiagnosticPos pos, Set<Whitespace> ws, Stack<String> precedingTextFragments, String endingText) { List<BLangExpression> expressions = new ArrayList<>(); String originalValue = endingText; endingText = endingText == null ? "" : StringEscapeUtils.unescapeJava(endingText); addLiteralValue(pos, ws, TypeTags.STRING, endingText, originalValue); expressions.add((BLangExpression) exprNodeStack.pop()); while (!precedingTextFragments.empty()) { expressions.add((BLangExpression) exprNodeStack.pop()); String textFragment = precedingTextFragments.pop(); originalValue = textFragment;/* w ww .j a v a 2 s . c o m*/ textFragment = textFragment == null ? "" : StringEscapeUtils.unescapeJava(textFragment); addLiteralValue(pos, ws, TypeTags.STRING, textFragment, originalValue); expressions.add((BLangExpression) exprNodeStack.pop()); } Collections.reverse(expressions); return expressions; }
From source file:org.trnltk.experiment.morphology.ambiguity.DataDiffUtil.java
/** * Reduce the number of edits by eliminating operationally trivial equalities. * * @param diffs LinkedList of Diff objects. *//*ww w . j av a2s . c o m*/ public void diff_cleanupEfficiency(LinkedList<Diff<T>> diffs) { if (diffs.isEmpty()) { return; } boolean changes = false; Stack<Diff> equalities = new Stack<Diff>(); // Stack of equalities. List<T> lastequality = null; // Always equal to equalities.lastElement().text ListIterator<Diff<T>> pointer = diffs.listIterator(); // Is there an insertion operation before the last equality. boolean pre_ins = false; // Is there a deletion operation before the last equality. boolean pre_del = false; // Is there an insertion operation after the last equality. boolean post_ins = false; // Is there a deletion operation after the last equality. boolean post_del = false; Diff<T> thisDiff = pointer.next(); Diff<T> safeDiff = thisDiff; // The last Diff that is known to be unsplitable. while (thisDiff != null) { if (thisDiff.operation == Operation.EQUAL) { // Equality found. if (thisDiff.text.size() < Diff_EditCost && (post_ins || post_del)) { // Candidate found. equalities.push(thisDiff); pre_ins = post_ins; pre_del = post_del; lastequality = thisDiff.text; } else { // Not a candidate, and can never become one. equalities.clear(); lastequality = null; safeDiff = thisDiff; } post_ins = post_del = false; } else { // An insertion or deletion. if (thisDiff.operation == Operation.DELETE) { post_del = true; } else { post_ins = true; } /* * Five types to be split: * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del> * <ins>A</ins>X<ins>C</ins><del>D</del> * <ins>A</ins><del>B</del>X<ins>C</ins> * <ins>A</del>X<ins>C</ins><del>D</del> * <ins>A</ins><del>B</del>X<del>C</del> */ if (lastequality != null && ((pre_ins && pre_del && post_ins && post_del) || ((lastequality.size() < Diff_EditCost / 2) && ((pre_ins ? 1 : 0) + (pre_del ? 1 : 0) + (post_ins ? 1 : 0) + (post_del ? 1 : 0)) == 3))) { //System.out.println("Splitting: '" + lastequality + "'"); // Walk back to offending equality. while (thisDiff != equalities.lastElement()) { thisDiff = pointer.previous(); } pointer.next(); // Replace equality with a delete. pointer.set(new Diff(Operation.DELETE, lastequality)); // Insert a corresponding an insert. pointer.add(thisDiff = new Diff(Operation.INSERT, lastequality)); equalities.pop(); // Throw away the equality we just deleted. lastequality = null; if (pre_ins && pre_del) { // No changes made which could affect previous entry, keep going. post_ins = post_del = true; equalities.clear(); safeDiff = thisDiff; } else { if (!equalities.empty()) { // Throw away the previous equality (it needs to be reevaluated). equalities.pop(); } if (equalities.empty()) { // There are no previous questionable equalities, // walk back to the last known safe diff. thisDiff = safeDiff; } else { // There is an equality we can fall back to. thisDiff = equalities.lastElement(); } while (thisDiff != pointer.previous()) { // Intentionally empty loop. } post_ins = post_del = false; } changes = true; } } thisDiff = pointer.hasNext() ? pointer.next() : null; } if (changes) { diff_cleanupMerge(diffs); } }