Browse Source

Fix javadoc org.eclipse.jgit diff package

Change-Id: I7162d72916abc8533ad37e8b17335ff4a70d6519
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
stable-4.10
Matthias Sohn 7 years ago
parent
commit
4d8233f237
  1. 13
      org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
  2. 24
      org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffAlgorithm.java
  3. 28
      org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java
  4. 45
      org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java
  5. 109
      org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
  6. 64
      org.eclipse.jgit/src/org/eclipse/jgit/diff/Edit.java
  7. 9
      org.eclipse.jgit/src/org/eclipse/jgit/diff/EditList.java
  8. 9
      org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequence.java
  9. 11
      org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequenceComparator.java
  10. 21
      org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequencePair.java
  11. 6
      org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java
  12. 16
      org.eclipse.jgit/src/org/eclipse/jgit/diff/LowLevelDiffAlgorithm.java
  13. 5
      org.eclipse.jgit/src/org/eclipse/jgit/diff/MyersDiff.java
  14. 6
      org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java
  15. 20
      org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
  16. 9
      org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java
  17. 50
      org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
  18. 12
      org.eclipse.jgit/src/org/eclipse/jgit/diff/Sequence.java
  19. 3
      org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java
  20. 9
      org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
  21. 14
      org.eclipse.jgit/src/org/eclipse/jgit/diff/Subsequence.java
  22. 8
      org.eclipse.jgit/src/org/eclipse/jgit/diff/SubsequenceComparator.java

13
org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java

@ -55,13 +55,13 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.ObjectStream;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
import org.eclipse.jgit.treewalk.filter.PathFilter;
/**
* Supplies the content of a file for {@link DiffFormatter}.
* Supplies the content of a file for
* {@link org.eclipse.jgit.diff.DiffFormatter}.
* <p>
* A content source is not thread-safe. Sources may contain state, including
* information about the last ObjectLoader they returned. Callers must be
@ -83,8 +83,9 @@ public abstract class ContentSource {
/**
* Construct a content source for a working directory.
*
* If the iterator is a {@link FileTreeIterator} an optimized version is
* used that doesn't require seeking through a TreeWalk.
* If the iterator is a {@link org.eclipse.jgit.treewalk.FileTreeIterator}
* an optimized version is used that doesn't require seeking through a
* TreeWalk.
*
* @param iterator
* the iterator to obtain source files through.
@ -102,7 +103,7 @@ public abstract class ContentSource {
* @param id
* blob id of the file, if known.
* @return the size in bytes.
* @throws IOException
* @throws java.io.IOException
* the file cannot be accessed.
*/
public abstract long size(String path, ObjectId id) throws IOException;
@ -117,7 +118,7 @@ public abstract class ContentSource {
* @return a loader that can supply the content of the file. The loader must
* be used before another loader can be obtained from this same
* source.
* @throws IOException
* @throws java.io.IOException
* the file cannot be accessed.
*/
public abstract ObjectLoader open(String path, ObjectId id)

24
org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffAlgorithm.java

@ -44,7 +44,8 @@
package org.eclipse.jgit.diff;
/**
* Compares two {@link Sequence}s to create an {@link EditList} of changes.
* Compares two {@link org.eclipse.jgit.diff.Sequence}s to create an
* {@link org.eclipse.jgit.diff.EditList} of changes.
* <p>
* An algorithm's {@code diff} method must be callable from concurrent threads
* without data collisions. This permits some algorithms to use a singleton
@ -69,6 +70,8 @@ public abstract class DiffAlgorithm {
}
/**
* Get diff algorithm
*
* @param alg
* the diff algorithm for which an implementation should be
* returned
@ -88,18 +91,18 @@ public abstract class DiffAlgorithm {
/**
* Compare two sequences and identify a list of edits between them.
*
* @param <S>
* type of sequence being compared.
* @param cmp
* the comparator supplying the element equivalence function.
* @param a
* the first (also known as old or pre-image) sequence. Edits
* returned by this algorithm will reference indexes using the
* 'A' side: {@link Edit#getBeginA()}, {@link Edit#getEndA()}.
* 'A' side: {@link org.eclipse.jgit.diff.Edit#getBeginA()},
* {@link org.eclipse.jgit.diff.Edit#getEndA()}.
* @param b
* the second (also known as new or post-image) sequence. Edits
* returned by this algorithm will reference indexes using the
* 'B' side: {@link Edit#getBeginB()}, {@link Edit#getEndB()}.
* 'B' side: {@link org.eclipse.jgit.diff.Edit#getBeginB()},
* {@link org.eclipse.jgit.diff.Edit#getEndB()}.
* @return a modifiable edit list comparing the two sequences. If empty, the
* sequences are identical according to {@code cmp}'s rules. The
* result list is never null.
@ -244,20 +247,21 @@ public abstract class DiffAlgorithm {
* proven to have no common starting or ending elements. The expected
* elimination of common starting and ending elements is automatically
* performed by the {@link #diff(SequenceComparator, Sequence, Sequence)}
* method, which invokes this method using {@link Subsequence}s.
* method, which invokes this method using
* {@link org.eclipse.jgit.diff.Subsequence}s.
*
* @param <S>
* type of sequence being compared.
* @param cmp
* the comparator supplying the element equivalence function.
* @param a
* the first (also known as old or pre-image) sequence. Edits
* returned by this algorithm will reference indexes using the
* 'A' side: {@link Edit#getBeginA()}, {@link Edit#getEndA()}.
* 'A' side: {@link org.eclipse.jgit.diff.Edit#getBeginA()},
* {@link org.eclipse.jgit.diff.Edit#getEndA()}.
* @param b
* the second (also known as new or post-image) sequence. Edits
* returned by this algorithm will reference indexes using the
* 'B' side: {@link Edit#getBeginB()}, {@link Edit#getEndB()}.
* 'B' side: {@link org.eclipse.jgit.diff.Edit#getBeginB()},
* {@link org.eclipse.jgit.diff.Edit#getEndB()}.
* @return a modifiable edit list comparing the two sequences.
*/
public abstract <S extends Sequence> EditList diffNonCommon(

28
org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java

@ -51,7 +51,9 @@ import org.eclipse.jgit.lib.Config.SectionParser;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.util.StringUtils;
/** Keeps track of diff related configuration options. */
/**
* Keeps track of diff related configuration options.
*/
public class DiffConfig {
/** Key for {@link Config#get(SectionParser)}. */
public static final Config.SectionParser<DiffConfig> KEY = DiffConfig::new;
@ -83,22 +85,38 @@ public class DiffConfig {
ConfigConstants.CONFIG_KEY_RENAMELIMIT, 200);
}
/** @return true if the prefix "a/" and "b/" should be suppressed. */
/**
* If prefix should be suppressed
*
* @return true if the prefix "a/" and "b/" should be suppressed
*/
public boolean isNoPrefix() {
return noPrefix;
}
/** @return true if rename detection is enabled by default. */
/**
* If rename detection is enabled
*
* @return true if rename detection is enabled by default
*/
public boolean isRenameDetectionEnabled() {
return renameDetectionType != RenameDetectionType.FALSE;
}
/** @return type of rename detection to perform. */
/**
* Get the rename detection type
*
* @return type of rename detection to perform
*/
public RenameDetectionType getRenameDetectionType() {
return renameDetectionType;
}
/** @return limit on number of paths to perform inexact rename detection. */
/**
* Get the rename limit
*
* @return limit on number of paths to perform inexact rename detection
*/
public int getRenameLimit() {
return renameLimit;
}

45
org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java

@ -58,7 +58,9 @@ import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilterMarker;
/** A value class representing a change to a file */
/**
* A value class representing a change to a file
*/
public class DiffEntry {
/** Magical SHA1 used for file adds or deletes */
static final AbbreviatedObjectId A_ZERO = AbbreviatedObjectId
@ -107,9 +109,9 @@ public class DiffEntry {
* @param walk
* the TreeWalk to walk through. Must have exactly two trees.
* @return headers describing the changed files.
* @throws IOException
* @throws java.io.IOException
* the repository cannot be accessed.
* @throws IllegalArgumentException
* @throws java.lang.IllegalArgumentException
* When given TreeWalk doesn't have exactly two trees.
*/
public static List<DiffEntry> scan(TreeWalk walk) throws IOException {
@ -127,9 +129,9 @@ public class DiffEntry {
* @param includeTrees
* include tree objects.
* @return headers describing the changed files.
* @throws IOException
* @throws java.io.IOException
* the repository cannot be accessed.
* @throws IllegalArgumentException
* @throws java.lang.IllegalArgumentException
* when {@code includeTrees} is true and given TreeWalk is
* recursive. Or when given TreeWalk doesn't have exactly two
* trees
@ -155,9 +157,9 @@ public class DiffEntry {
* queried through {{@link #isMarked(int)} (with the index from
* this passed array).
* @return headers describing the changed files.
* @throws IOException
* @throws java.io.IOException
* the repository cannot be accessed.
* @throws IllegalArgumentException
* @throws java.lang.IllegalArgumentException
* when {@code includeTrees} is true and given TreeWalk is
* recursive. Or when given TreeWalk doesn't have exactly two
* trees
@ -392,12 +394,20 @@ public class DiffEntry {
return side == Side.OLD ? getOldPath() : getNewPath();
}
/** @return the old file mode, if described in the patch */
/**
* Get the old file mode
*
* @return the old file mode, if described in the patch
*/
public FileMode getOldMode() {
return oldMode;
}
/** @return the new file mode, if described in the patch */
/**
* Get the new file mode
*
* @return the new file mode, if described in the patch
*/
public FileMode getNewMode() {
return newMode;
}
@ -413,15 +423,22 @@ public class DiffEntry {
return side == Side.OLD ? getOldMode() : getNewMode();
}
/** @return the type of change this patch makes on {@link #getNewPath()} */
/**
* Get the change type
*
* @return the type of change this patch makes on {@link #getNewPath()}
*/
public ChangeType getChangeType() {
return changeType;
}
/**
* Get similarity score
*
* @return similarity score between {@link #getOldPath()} and
* {@link #getNewPath()} if {@link #getChangeType()} is
* {@link ChangeType#COPY} or {@link ChangeType#RENAME}.
* {@link org.eclipse.jgit.diff.DiffEntry.ChangeType#COPY} or
* {@link org.eclipse.jgit.diff.DiffEntry.ChangeType#RENAME}.
*/
public int getScore() {
return score;
@ -466,10 +483,9 @@ public class DiffEntry {
*
* @param index
* the index of the tree filter to check for (must be between 0
* and {@link Integer#SIZE}).
*
* @return true, if the tree filter matched; false if not
* and {@link java.lang.Integer#SIZE}).
* @since 2.3
* @return a boolean.
*/
public boolean isMarked(int index) {
return (treeFilterMarks & (1L << index)) != 0;
@ -498,6 +514,7 @@ public class DiffEntry {
return side == Side.OLD ? getOldId() : getNewId();
}
/** {@inheritDoc} */
@SuppressWarnings("nls")
@Override
public String toString() {

109
org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java

@ -84,7 +84,6 @@ import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.patch.FileHeader;
import org.eclipse.jgit.patch.FileHeader.PatchType;
import org.eclipse.jgit.patch.HunkHeader;
import org.eclipse.jgit.revwalk.FollowFilter;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
@ -100,7 +99,6 @@ import org.eclipse.jgit.treewalk.filter.NotIgnoredFilter;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.util.QuotedString;
import org.eclipse.jgit.util.io.DisabledOutputStream;
/**
* Format a Git style patch script.
@ -155,7 +153,11 @@ public class DiffFormatter implements AutoCloseable {
this.out = out;
}
/** @return the stream we are outputting data to. */
/**
* Get output stream
*
* @return the stream we are outputting data to
*/
protected OutputStream getOutputStream() {
return out;
}
@ -324,7 +326,11 @@ public class DiffFormatter implements AutoCloseable {
return this.newPrefix;
}
/** @return true if rename detection is enabled. */
/**
* Get if rename detection is enabled
*
* @return true if rename detection is enabled
*/
public boolean isDetectRenames() {
return renameDetector != null;
}
@ -348,7 +354,11 @@ public class DiffFormatter implements AutoCloseable {
renameDetector = null;
}
/** @return the rename detector if rename detection is enabled. */
/**
* Get rename detector
*
* @return the rename detector if rename detection is enabled
*/
public RenameDetector getRenameDetector() {
return renameDetector;
}
@ -366,9 +376,10 @@ public class DiffFormatter implements AutoCloseable {
/**
* Set the filter to produce only specific paths.
*
* If the filter is an instance of {@link FollowFilter}, the filter path
* will be updated during successive scan or format invocations. The updated
* path can be obtained from {@link #getPathFilter()}.
* If the filter is an instance of
* {@link org.eclipse.jgit.revwalk.FollowFilter}, the filter path will be
* updated during successive scan or format invocations. The updated path
* can be obtained from {@link #getPathFilter()}.
*
* @param filter
* the tree filter to apply.
@ -377,7 +388,11 @@ public class DiffFormatter implements AutoCloseable {
pathFilter = filter != null ? filter : TreeFilter.ALL;
}
/** @return the current path filter. */
/**
* Get path filter
*
* @return the current path filter
*/
public TreeFilter getPathFilter() {
return pathFilter;
}
@ -385,7 +400,7 @@ public class DiffFormatter implements AutoCloseable {
/**
* Flush the underlying output stream of this formatter.
*
* @throws IOException
* @throws java.io.IOException
* the stream's own flush method threw an exception.
*/
public void flush() throws IOException {
@ -393,6 +408,8 @@ public class DiffFormatter implements AutoCloseable {
}
/**
* {@inheritDoc}
* <p>
* Release the internal ObjectReader state.
*
* @since 4.0
@ -409,8 +426,8 @@ public class DiffFormatter implements AutoCloseable {
*
* No output is created, instead only the file paths that are different are
* returned. Callers may choose to format these paths themselves, or convert
* them into {@link FileHeader} instances with a complete edit list by
* calling {@link #toFileHeader(DiffEntry)}.
* them into {@link org.eclipse.jgit.patch.FileHeader} instances with a
* complete edit list by calling {@link #toFileHeader(DiffEntry)}.
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
@ -420,7 +437,7 @@ public class DiffFormatter implements AutoCloseable {
* @param b
* the new (or updated) side or null
* @return the paths that are different.
* @throws IOException
* @throws java.io.IOException
* trees cannot be read or file contents cannot be read.
*/
public List<DiffEntry> scan(AnyObjectId a, AnyObjectId b)
@ -439,8 +456,8 @@ public class DiffFormatter implements AutoCloseable {
*
* No output is created, instead only the file paths that are different are
* returned. Callers may choose to format these paths themselves, or convert
* them into {@link FileHeader} instances with a complete edit list by
* calling {@link #toFileHeader(DiffEntry)}.
* them into {@link org.eclipse.jgit.patch.FileHeader} instances with a
* complete edit list by calling {@link #toFileHeader(DiffEntry)}.
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
@ -450,7 +467,7 @@ public class DiffFormatter implements AutoCloseable {
* @param b
* the new (or updated) side or null
* @return the paths that are different.
* @throws IOException
* @throws java.io.IOException
* trees cannot be read or file contents cannot be read.
*/
public List<DiffEntry> scan(RevTree a, RevTree b) throws IOException {
@ -476,15 +493,15 @@ public class DiffFormatter implements AutoCloseable {
*
* No output is created, instead only the file paths that are different are
* returned. Callers may choose to format these paths themselves, or convert
* them into {@link FileHeader} instances with a complete edit list by
* calling {@link #toFileHeader(DiffEntry)}.
* them into {@link org.eclipse.jgit.patch.FileHeader} instances with a
* complete edit list by calling {@link #toFileHeader(DiffEntry)}.
*
* @param a
* the old (or previous) side.
* @param b
* the new (or updated) side.
* @return the paths that are different.
* @throws IOException
* @throws java.io.IOException
* trees cannot be read or file contents cannot be read.
*/
public List<DiffEntry> scan(AbstractTreeIterator a, AbstractTreeIterator b)
@ -596,7 +613,7 @@ public class DiffFormatter implements AutoCloseable {
* the old (or previous) side or null
* @param b
* the new (or updated) side or null
* @throws IOException
* @throws java.io.IOException
* trees cannot be read, file contents cannot be read, or the
* patch cannot be output.
*/
@ -618,7 +635,7 @@ public class DiffFormatter implements AutoCloseable {
* the old (or previous) side or null
* @param b
* the new (or updated) side or null
* @throws IOException
* @throws java.io.IOException
* trees cannot be read, file contents cannot be read, or the
* patch cannot be output.
*/
@ -639,7 +656,7 @@ public class DiffFormatter implements AutoCloseable {
* the old (or previous) side or null
* @param b
* the new (or updated) side or null
* @throws IOException
* @throws java.io.IOException
* trees cannot be read, file contents cannot be read, or the
* patch cannot be output.
*/
@ -655,7 +672,7 @@ public class DiffFormatter implements AutoCloseable {
*
* @param entries
* entries describing the affected files.
* @throws IOException
* @throws java.io.IOException
* a file's content cannot be read, or the output stream cannot
* be written to.
*/
@ -669,7 +686,7 @@ public class DiffFormatter implements AutoCloseable {
*
* @param ent
* the entry to be formatted.
* @throws IOException
* @throws java.io.IOException
* a file's content cannot be read, or the output stream cannot
* be written to.
*/
@ -712,11 +729,13 @@ public class DiffFormatter implements AutoCloseable {
* existing file header containing the header lines to copy.
* @param a
* text source for the pre-image version of the content. This
* must match the content of {@link FileHeader#getOldId()}.
* must match the content of
* {@link org.eclipse.jgit.patch.FileHeader#getOldId()}.
* @param b
* text source for the post-image version of the content. This
* must match the content of {@link FileHeader#getNewId()}.
* @throws IOException
* must match the content of
* {@link org.eclipse.jgit.patch.FileHeader#getNewId()}.
* @throws java.io.IOException
* writing to the supplied stream failed.
*/
public void format(final FileHeader head, final RawText a, final RawText b)
@ -743,7 +762,7 @@ public class DiffFormatter implements AutoCloseable {
* the text A which was compared
* @param b
* the text B which was compared
* @throws IOException
* @throws java.io.IOException
*/
public void format(final EditList edits, final RawText a, final RawText b)
throws IOException {
@ -791,7 +810,7 @@ public class DiffFormatter implements AutoCloseable {
* RawText for accessing raw data
* @param line
* the line number within text
* @throws IOException
* @throws java.io.IOException
*/
protected void writeContextLine(final RawText text, final int line)
throws IOException {
@ -809,7 +828,7 @@ public class DiffFormatter implements AutoCloseable {
* RawText for accessing raw data
* @param line
* the line number within text
* @throws IOException
* @throws java.io.IOException
*/
protected void writeAddedLine(final RawText text, final int line)
throws IOException {
@ -823,7 +842,7 @@ public class DiffFormatter implements AutoCloseable {
* RawText for accessing raw data
* @param line
* the line number within text
* @throws IOException
* @throws java.io.IOException
*/
protected void writeRemovedLine(final RawText text, final int line)
throws IOException {
@ -841,7 +860,7 @@ public class DiffFormatter implements AutoCloseable {
* within second source
* @param bEndLine
* within second source
* @throws IOException
* @throws java.io.IOException
*/
protected void writeHunkHeader(int aStartLine, int aEndLine,
int bStartLine, int bEndLine) throws IOException {
@ -894,7 +913,7 @@ public class DiffFormatter implements AutoCloseable {
* the text object to obtain the line from.
* @param cur
* line number to output.
* @throws IOException
* @throws java.io.IOException
* the stream threw an exception while writing to it.
*/
protected void writeLine(final char prefix, final RawText text,
@ -905,24 +924,26 @@ public class DiffFormatter implements AutoCloseable {
}
/**
* Creates a {@link FileHeader} representing the given {@link DiffEntry}
* Creates a {@link org.eclipse.jgit.patch.FileHeader} representing the
* given {@link org.eclipse.jgit.diff.DiffEntry}
* <p>
* This method does not use the OutputStream associated with this
* DiffFormatter instance. It is therefore safe to instantiate this
* DiffFormatter instance with a {@link DisabledOutputStream} if this method
* is the only one that will be used.
* DiffFormatter instance with a
* {@link org.eclipse.jgit.util.io.DisabledOutputStream} if this method is
* the only one that will be used.
*
* @param ent
* the DiffEntry to create the FileHeader for
* @return a FileHeader representing the DiffEntry. The FileHeader's buffer
* will contain only the header of the diff output. It will also
* contain one {@link HunkHeader}.
* @throws IOException
* contain one {@link org.eclipse.jgit.patch.HunkHeader}.
* @throws java.io.IOException
* the stream threw an exception while writing to it, or one of
* the blobs referenced by the DiffEntry could not be read.
* @throws CorruptObjectException
* @throws org.eclipse.jgit.errors.CorruptObjectException
* one of the blobs referenced by the DiffEntry is corrupt.
* @throws MissingObjectException
* @throws org.eclipse.jgit.errors.MissingObjectException
* one of the blobs referenced by the DiffEntry is missing.
*/
public FileHeader toFileHeader(DiffEntry ent) throws IOException,
@ -1046,12 +1067,12 @@ public class DiffFormatter implements AutoCloseable {
* @param o
* The stream the formatter will write the first header line to
* @param type
* The {@link ChangeType}
* The {@link org.eclipse.jgit.diff.DiffEntry.ChangeType}
* @param oldPath
* old path to the file
* @param newPath
* new path to the file
* @throws IOException
* @throws java.io.IOException
* the stream threw an exception while writing to it.
*/
protected void formatGitDiffFirstHeaderLine(ByteArrayOutputStream o,
@ -1136,11 +1157,13 @@ public class DiffFormatter implements AutoCloseable {
}
/**
* Format index line
*
* @param o
* the stream the formatter will write line data to
* @param ent
* the DiffEntry to create the FileHeader for
* @throws IOException
* @throws java.io.IOException
* writing to the supplied stream failed.
*/
protected void formatIndexLine(OutputStream o, DiffEntry ent)

64
org.eclipse.jgit/src/org/eclipse/jgit/diff/Edit.java

@ -118,7 +118,11 @@ public class Edit {
endB = be;
}
/** @return the type of this region */
/**
* Get type
*
* @return the type of this region
*/
public final Type getType() {
if (beginA < endA) {
if (beginB < endB)
@ -134,37 +138,66 @@ public class Edit {
}
}
/** @return true if the edit is empty (lengths of both a and b is zero). */
/**
* Whether edit is empty
*
* @return {@code true} if the edit is empty (lengths of both a and b is
* zero)
*/
public final boolean isEmpty() {
return beginA == endA && beginB == endB;
}
/** @return start point in sequence A. */
/**
* Get start point in sequence A
*
* @return start point in sequence A
*/
public final int getBeginA() {
return beginA;
}
/** @return end point in sequence A. */
/**
* Get end point in sequence A
*
* @return end point in sequence A
*/
public final int getEndA() {
return endA;
}
/** @return start point in sequence B. */
/**
* Get start point in sequence B
*
* @return start point in sequence B
*/
public final int getBeginB() {
return beginB;
}
/** @return end point in sequence B. */
/**
* Get end point in sequence B
*
* @return end point in sequence B
*/
public final int getEndB() {
return endB;
}
/** @return length of the region in A. */
/**
* Get length of the region in A
*
* @return length of the region in A
*/
public final int getLengthA() {
return endA - beginA;
}
/** @return length of the region in B. */
/**
* Get length of the region in B
*
* @return return length of the region in B
*/
public final int getLengthB() {
return endB - beginB;
}
@ -210,17 +243,23 @@ public class Edit {
return new Edit(cut.endA, endA, cut.endB, endB);
}
/** Increase {@link #getEndA()} by 1. */
/**
* Increase {@link #getEndA()} by 1.
*/
public void extendA() {
endA++;
}
/** Increase {@link #getEndB()} by 1. */
/**
* Increase {@link #getEndB()} by 1.
*/
public void extendB() {
endB++;
}
/** Swap A and B, so the edit goes the other direction. */
/**
* Swap A and B, so the edit goes the other direction.
*/
public void swap() {
final int sBegin = beginA;
final int sEnd = endA;
@ -232,11 +271,13 @@ public class Edit {
endB = sEnd;
}
/** {@inheritDoc} */
@Override
public int hashCode() {
return beginA ^ endA;
}
/** {@inheritDoc} */
@Override
public boolean equals(final Object o) {
if (o instanceof Edit) {
@ -247,6 +288,7 @@ public class Edit {
return false;
}
/** {@inheritDoc} */
@SuppressWarnings("nls")
@Override
public String toString() {

9
org.eclipse.jgit/src/org/eclipse/jgit/diff/EditList.java

@ -45,7 +45,9 @@ package org.eclipse.jgit.diff;
import java.util.ArrayList;
/** Specialized list of {@link Edit}s in a document. */
/**
* Specialized list of {@link org.eclipse.jgit.diff.Edit}s in a document.
*/
public class EditList extends ArrayList<Edit> {
private static final long serialVersionUID = 1L;
@ -62,7 +64,9 @@ public class EditList extends ArrayList<Edit> {
return res;
}
/** Create a new, empty edit list. */
/**
* Create a new, empty edit list.
*/
public EditList() {
super(16);
}
@ -78,6 +82,7 @@ public class EditList extends ArrayList<Edit> {
super(capacity);
}
/** {@inheritDoc} */
@Override
public String toString() {
return "EditList" + super.toString(); //$NON-NLS-1$

9
org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequence.java

@ -44,13 +44,15 @@
package org.eclipse.jgit.diff;
/**
* Wraps a {@link Sequence} to assign hash codes to elements.
* Wraps a {@link org.eclipse.jgit.diff.Sequence} to assign hash codes to
* elements.
* <p>
* This sequence acts as a proxy for the real sequence, caching element hash
* codes so they don't need to be recomputed each time. Sequences of this type
* must be used with a {@link HashedSequenceComparator}.
* must be used with a {@link org.eclipse.jgit.diff.HashedSequenceComparator}.
* <p>
* To construct an instance of this type use {@link HashedSequencePair}.
* To construct an instance of this type use
* {@link org.eclipse.jgit.diff.HashedSequencePair}.
*
* @param <S>
* the base sequence type.
@ -65,6 +67,7 @@ public final class HashedSequence<S extends Sequence> extends Sequence {
this.hashes = hashes;
}
/** {@inheritDoc} */
@Override
public int size() {
return base.size();

11
org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequenceComparator.java

@ -44,13 +44,16 @@
package org.eclipse.jgit.diff;
/**
* Wrap another comparator for use with {@link HashedSequence}.
* Wrap another comparator for use with
* {@link org.eclipse.jgit.diff.HashedSequence}.
* <p>
* This comparator acts as a proxy for the real comparator, evaluating the
* cached hash code before testing the underlying comparator's equality.
* Comparators of this type must be used with a {@link HashedSequence}.
* Comparators of this type must be used with a
* {@link org.eclipse.jgit.diff.HashedSequence}.
* <p>
* To construct an instance of this type use {@link HashedSequencePair}.
* To construct an instance of this type use
* {@link org.eclipse.jgit.diff.HashedSequencePair}.
*
* @param <S>
* the base sequence type.
@ -63,6 +66,7 @@ public final class HashedSequenceComparator<S extends Sequence> extends
this.cmp = cmp;
}
/** {@inheritDoc} */
@Override
public boolean equals(HashedSequence<S> a, int ai, //
HashedSequence<S> b, int bi) {
@ -70,6 +74,7 @@ public final class HashedSequenceComparator<S extends Sequence> extends
&& cmp.equals(a.base, ai, b.base, bi);
}
/** {@inheritDoc} */
@Override
public int hash(HashedSequence<S> seq, int ptr) {
return seq.hashes[ptr];

21
org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequencePair.java

@ -44,7 +44,8 @@
package org.eclipse.jgit.diff;
/**
* Wraps two {@link Sequence} instances to cache their element hash codes.
* Wraps two {@link org.eclipse.jgit.diff.Sequence} instances to cache their
* element hash codes.
* <p>
* This pair wraps two sequences that contain cached hash codes for the input
* sequences.
@ -79,19 +80,31 @@ public class HashedSequencePair<S extends Sequence> {
this.baseB = b;
}
/** @return obtain a comparator that uses the cached hash codes. */
/**
* Get comparator
*
* @return obtain a comparator that uses the cached hash codes
*/
public HashedSequenceComparator<S> getComparator() {
return new HashedSequenceComparator<>(cmp);
}
/** @return wrapper around A that includes cached hash codes. */
/**
* Get A
*
* @return wrapper around A that includes cached hash codes
*/
public HashedSequence<S> getA() {
if (cachedA == null)
cachedA = wrap(baseA);
return cachedA;
}
/** @return wrapper around B that includes cached hash codes. */
/**
* Get B
*
* @return wrapper around B that includes cached hash codes
*/
public HashedSequence<S> getB() {
if (cachedB == null)
cachedB = wrap(baseB);

6
org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java

@ -85,8 +85,9 @@ import java.util.List;
* So long as {@link #setMaxChainLength(int)} is a small constant (such as 64),
* the algorithm runs in O(N * D) time, where N is the sum of the input lengths
* and D is the number of edits in the resulting EditList. If the supplied
* {@link SequenceComparator} has a good hash function, this implementation
* typically out-performs {@link MyersDiff}, even though its theoretical running
* {@link org.eclipse.jgit.diff.SequenceComparator} has a good hash function,
* this implementation typically out-performs
* {@link org.eclipse.jgit.diff.MyersDiff}, even though its theoretical running
* time is the same.
* <p>
* This implementation has an internal limitation that prevents it from handling
@ -130,6 +131,7 @@ public class HistogramDiff extends LowLevelDiffAlgorithm {
maxChainLength = maxLen;
}
/** {@inheritDoc} */
@Override
public <S extends Sequence> void diffNonCommon(EditList edits,
HashedSequenceComparator<S> cmp, HashedSequence<S> a,

16
org.eclipse.jgit/src/org/eclipse/jgit/diff/LowLevelDiffAlgorithm.java

@ -43,8 +43,11 @@
package org.eclipse.jgit.diff;
/** Compares two sequences primarily based upon hash codes. */
/**
* Compares two sequences primarily based upon hash codes.
*/
public abstract class LowLevelDiffAlgorithm extends DiffAlgorithm {
/** {@inheritDoc} */
@Override
public <S extends Sequence> EditList diffNonCommon(
SequenceComparator<? super S> cmp, S a, S b) {
@ -67,10 +70,9 @@ public abstract class LowLevelDiffAlgorithm extends DiffAlgorithm {
* proven to have no common starting or ending elements. The expected
* elimination of common starting and ending elements is automatically
* performed by the {@link #diff(SequenceComparator, Sequence, Sequence)}
* method, which invokes this method using {@link Subsequence}s.
* method, which invokes this method using
* {@link org.eclipse.jgit.diff.Subsequence}s.
*
* @param <S>
* type of sequence being compared.
* @param edits
* result list to append the region's edits onto.
* @param cmp
@ -78,11 +80,13 @@ public abstract class LowLevelDiffAlgorithm extends DiffAlgorithm {
* @param a
* the first (also known as old or pre-image) sequence. Edits
* returned by this algorithm will reference indexes using the
* 'A' side: {@link Edit#getBeginA()}, {@link Edit#getEndA()}.
* 'A' side: {@link org.eclipse.jgit.diff.Edit#getBeginA()},
* {@link org.eclipse.jgit.diff.Edit#getEndA()}.
* @param b
* the second (also known as new or post-image) sequence. Edits
* returned by this algorithm will reference indexes using the
* 'B' side: {@link Edit#getBeginB()}, {@link Edit#getEndB()}.
* 'B' side: {@link org.eclipse.jgit.diff.Edit#getBeginB()},
* {@link org.eclipse.jgit.diff.Edit#getEndB()}.
* @param region
* the region being compared within the two sequences.
*/

5
org.eclipse.jgit/src/org/eclipse/jgit/diff/MyersDiff.java

@ -557,7 +557,10 @@ if (k < beginK || k > endK)
}
/**
* @param args two filenames specifying the contents to be diffed
* Main method
*
* @param args
* two filenames specifying the contents to be diffed
*/
public static void main(String[] args) {
if (args.length != 2) {

6
org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java

@ -58,7 +58,9 @@ public class PatchIdDiffFormatter extends DiffFormatter {
private final MessageDigest digest;
/** Initialize a formatter to compute a patch id. */
/**
* Initialize a formatter to compute a patch id.
*/
public PatchIdDiffFormatter() {
super(new DigestOutputStream(NullOutputStream.INSTANCE,
Constants.newMessageDigest()));
@ -74,12 +76,14 @@ public class PatchIdDiffFormatter extends DiffFormatter {
return ObjectId.fromRaw(digest.digest());
}
/** {@inheritDoc} */
@Override
protected void writeHunkHeader(int aStartLine, int aEndLine,
int bStartLine, int bEndLine) throws IOException {
// The hunk header is not taken into account for patch id calculation
}
/** {@inheritDoc} */
@Override
protected void formatIndexLine(OutputStream o, DiffEntry ent)
throws IOException {

20
org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java

@ -103,7 +103,7 @@ public class RawText extends Sequence {
*
* @param file
* the text file.
* @throws IOException
* @throws java.io.IOException
* if Exceptions occur while reading the file
*/
public RawText(File file) throws IOException {
@ -111,6 +111,7 @@ public class RawText extends Sequence {
}
/** @return total number of items in the sequence. */
/** {@inheritDoc} */
@Override
public int size() {
// The line map is always 2 entries larger than the number of lines in
@ -135,7 +136,7 @@ public class RawText extends Sequence {
* @param i
* index of the line to extract. Note this is 0-based, so line
* number 1 is actually index 0.
* @throws IOException
* @throws java.io.IOException
* the stream write operation failed.
*/
public void writeLine(final OutputStream out, final int i)
@ -244,7 +245,7 @@ public class RawText extends Sequence {
* @param raw
* input stream containing the raw file content.
* @return true if raw is likely to be a binary file, false otherwise
* @throws IOException
* @throws java.io.IOException
* if input stream could not be read
*/
public static boolean isBinary(InputStream raw) throws IOException {
@ -301,17 +302,20 @@ public class RawText extends Sequence {
}
/**
* Read a blob object into RawText, or throw BinaryBlobException if
* the blob is binary.
* Read a blob object into RawText, or throw BinaryBlobException if the blob
* is binary.
*
* @param ldr
* the ObjectLoader for the blob
* @param threshold
* if the blob is larger than this size, it is always assumed to be binary.
* if the blob is larger than this size, it is always assumed to
* be binary.
* @since 4.10
* @return the RawText representing the blob.
* @throws BinaryBlobException if the blob contains binary data.
* @throws IOException if the input could not be read.
* @throws org.eclipse.jgit.errors.BinaryBlobException
* if the blob contains binary data.
* @throws java.io.IOException
* if the input could not be read.
*/
public static RawText load(ObjectLoader ldr, int threshold) throws IOException, BinaryBlobException {
long sz = ldr.getSize();

9
org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java

@ -50,7 +50,9 @@ import static org.eclipse.jgit.util.RawCharUtil.trimTrailingWhitespace;
import org.eclipse.jgit.util.IntList;
/** Equivalence function for {@link RawText}. */
/**
* Equivalence function for {@link org.eclipse.jgit.diff.RawText}.
*/
public abstract class RawTextComparator extends SequenceComparator<RawText> {
/** No special treatment. */
public static final RawTextComparator DEFAULT = new RawTextComparator() {
@ -134,7 +136,9 @@ public abstract class RawTextComparator extends SequenceComparator<RawText> {
}
};
/** Ignores leading whitespace. */
/**
* Ignore leading whitespace.
**/
public static final RawTextComparator WS_IGNORE_LEADING = new RawTextComparator() {
@Override
public boolean equals(RawText a, int ai, RawText b, int bi) {
@ -262,6 +266,7 @@ public abstract class RawTextComparator extends SequenceComparator<RawText> {
return hashRegion(seq.content, begin, end);
}
/** {@inheritDoc} */
@Override
public Edit reduceCommonStartEnd(RawText a, RawText b, Edit e) {
// This is a faster exact match based form that tries to improve

50
org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java

@ -65,7 +65,9 @@ import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Repository;
/** Detect and resolve object renames. */
/**
* Detect and resolve object renames.
*/
public class RenameDetector {
private static final int EXACT_RENAME_SCORE = 100;
@ -156,6 +158,8 @@ public class RenameDetector {
}
/**
* Get rename score
*
* @return minimum score required to pair an add/delete as a rename. The
* score ranges are within the bounds of (0, 100).
*/
@ -173,7 +177,7 @@ public class RenameDetector {
*
* @param score
* new rename score, must be within [0, 100].
* @throws IllegalArgumentException
* @throws java.lang.IllegalArgumentException
* the score was not within [0, 100].
*/
public void setRenameScore(int score) {
@ -184,6 +188,8 @@ public class RenameDetector {
}
/**
* Get break score
*
* @return the similarity score required to keep modified file pairs
* together. Any modify pairs that score below this will be broken
* apart into separate add/deletes. Values less than or equal to
@ -195,6 +201,8 @@ public class RenameDetector {
}
/**
* Set break score
*
* @param breakScore
* the similarity score required to keep modified file pairs
* together. Any modify pairs that score below this will be
@ -206,7 +214,11 @@ public class RenameDetector {
this.breakScore = breakScore;
}
/** @return limit on number of paths to perform inexact rename detection. */
/**
* Get rename limit
*
* @return limit on number of paths to perform inexact rename detection
*/
public int getRenameLimit() {
return renameLimit;
}
@ -250,7 +262,7 @@ public class RenameDetector {
*
* @param entriesToAdd
* one or more entries to add.
* @throws IllegalStateException
* @throws java.lang.IllegalStateException
* if {@code getEntries} was already invoked.
*/
public void addAll(Collection<DiffEntry> entriesToAdd) {
@ -290,7 +302,7 @@ public class RenameDetector {
*
* @param entry
* to add.
* @throws IllegalStateException
* @throws java.lang.IllegalStateException
* if {@code getEntries} was already invoked.
*/
public void add(DiffEntry entry) {
@ -302,9 +314,9 @@ public class RenameDetector {
* <p>
* This convenience function runs without a progress monitor.
*
* @return an unmodifiable list of {@link DiffEntry}s representing all files
* that have been changed.
* @throws IOException
* @return an unmodifiable list of {@link org.eclipse.jgit.diff.DiffEntry}s
* representing all files that have been changed.
* @throws java.io.IOException
* file contents cannot be read from the repository.
*/
public List<DiffEntry> compute() throws IOException {
@ -316,9 +328,9 @@ public class RenameDetector {
*
* @param pm
* report progress during the detection phases.
* @return an unmodifiable list of {@link DiffEntry}s representing all files
* that have been changed.
* @throws IOException
* @return an unmodifiable list of {@link org.eclipse.jgit.diff.DiffEntry}s
* representing all files that have been changed.
* @throws java.io.IOException
* file contents cannot be read from the repository.
*/
public List<DiffEntry> compute(ProgressMonitor pm) throws IOException {
@ -339,9 +351,9 @@ public class RenameDetector {
* reader to obtain objects from the repository with.
* @param pm
* report progress during the detection phases.
* @return an unmodifiable list of {@link DiffEntry}s representing all files
* that have been changed.
* @throws IOException
* @return an unmodifiable list of {@link org.eclipse.jgit.diff.DiffEntry}s
* representing all files that have been changed.
* @throws java.io.IOException
* file contents cannot be read from the repository.
*/
public List<DiffEntry> compute(ObjectReader reader, ProgressMonitor pm)
@ -357,9 +369,9 @@ public class RenameDetector {
* reader to obtain objects from the repository with.
* @param pm
* report progress during the detection phases.
* @return an unmodifiable list of {@link DiffEntry}s representing all files
* that have been changed.
* @throws IOException
* @return an unmodifiable list of {@link org.eclipse.jgit.diff.DiffEntry}s
* representing all files that have been changed.
* @throws java.io.IOException
* file contents cannot be read from the repository.
*/
public List<DiffEntry> compute(ContentSource.Pair reader, ProgressMonitor pm)
@ -393,7 +405,9 @@ public class RenameDetector {
return Collections.unmodifiableList(entries);
}
/** Reset this rename detector for another rename detection pass. */
/**
* Reset this rename detector for another rename detection pass.
*/
public void reset() {
entries = new ArrayList<>();
deleted = new ArrayList<>();

12
org.eclipse.jgit/src/org/eclipse/jgit/diff/Sequence.java

@ -52,13 +52,19 @@ package org.eclipse.jgit.diff;
* Unlike a List, the members of the sequence are not directly obtainable.
* <p>
* Implementations of Sequence are primarily intended for use in content
* difference detection algorithms, to produce an {@link EditList} of
* {@link Edit} instances describing how two Sequence instances differ.
* difference detection algorithms, to produce an
* {@link org.eclipse.jgit.diff.EditList} of {@link org.eclipse.jgit.diff.Edit}
* instances describing how two Sequence instances differ.
* <p>
* To be compared against another Sequence of the same type, a supporting
* {@link SequenceComparator} must also be supplied.
* {@link org.eclipse.jgit.diff.SequenceComparator} must also be supplied.
*/
public abstract class Sequence {
/** @return total number of items in the sequence. */
/**
* Get size
*
* @return size
*/
public abstract int size();
}

3
org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java

@ -44,7 +44,8 @@
package org.eclipse.jgit.diff;
/**
* Equivalence function for a {@link Sequence} compared by difference algorithm.
* Equivalence function for a {@link org.eclipse.jgit.diff.Sequence} compared by
* difference algorithm.
* <p>
* Difference algorithms can use a comparator to compare portions of two
* sequences and discover the minimal edits required to transform from one

9
org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java

@ -56,8 +56,9 @@ import org.eclipse.jgit.lib.ObjectStream;
* Index structure of lines/blocks in one file.
* <p>
* This structure can be used to compute an approximation of the similarity
* between two files. The index is used by {@link SimilarityRenameDetector} to
* compute scores between files.
* between two files. The index is used by
* {@link org.eclipse.jgit.diff.SimilarityRenameDetector} to compute scores
* between files.
* <p>
* To save space in memory, this index uses a space efficient encoding which
* will not exceed 1 MiB per instance. The index starts out at a smaller size
@ -114,9 +115,9 @@ public class SimilarityIndex {
* @param obj
* the object to hash
* @return similarity index for this object
* @throws IOException
* @throws java.io.IOException
* file contents cannot be read from the repository.
* @throws TableFullException
* @throws org.eclipse.jgit.diff.SimilarityIndex.TableFullException
* object hashing overflowed the storage capacity of the
* SimilarityIndex.
*/

14
org.eclipse.jgit/src/org/eclipse/jgit/diff/Subsequence.java

@ -44,11 +44,12 @@
package org.eclipse.jgit.diff;
/**
* Wraps a {@link Sequence} to have a narrower range of elements.
* Wraps a {@link org.eclipse.jgit.diff.Sequence} to have a narrower range of
* elements.
* <p>
* This sequence acts as a proxy for the real sequence, translating element
* indexes on the fly by adding {@code begin} to them. Sequences of this type
* must be used with a {@link SubsequenceComparator}.
* must be used with a {@link org.eclipse.jgit.diff.SubsequenceComparator}.
*
* @param <S>
* the base sequence type.
@ -57,8 +58,6 @@ public final class Subsequence<S extends Sequence> extends Sequence {
/**
* Construct a subsequence around the A region/base sequence.
*
* @param <S>
* the base sequence type.
* @param a
* the A sequence.
* @param region
@ -72,8 +71,6 @@ public final class Subsequence<S extends Sequence> extends Sequence {
/**
* Construct a subsequence around the B region/base sequence.
*
* @param <S>
* the base sequence type.
* @param b
* the B sequence.
* @param region
@ -87,8 +84,6 @@ public final class Subsequence<S extends Sequence> extends Sequence {
/**
* Adjust the Edit to reflect positions in the base sequence.
*
* @param <S>
* the base sequence type.
* @param e
* edit to adjust in-place. Prior to invocation the indexes are
* in terms of the two subsequences; after invocation the indexes
@ -110,8 +105,6 @@ public final class Subsequence<S extends Sequence> extends Sequence {
/**
* Adjust the Edits to reflect positions in the base sequence.
*
* @param <S>
* the base sequence type.
* @param edits
* edits to adjust in-place. Prior to invocation the indexes are
* in terms of the two subsequences; after invocation the indexes
@ -156,6 +149,7 @@ public final class Subsequence<S extends Sequence> extends Sequence {
this.size = end - begin;
}
/** {@inheritDoc} */
@Override
public int size() {
return size;

8
org.eclipse.jgit/src/org/eclipse/jgit/diff/SubsequenceComparator.java

@ -44,11 +44,13 @@
package org.eclipse.jgit.diff;
/**
* Wrap another comparator for use with {@link Subsequence}.
* Wrap another comparator for use with
* {@link org.eclipse.jgit.diff.Subsequence}.
* <p>
* This comparator acts as a proxy for the real comparator, translating element
* indexes on the fly by adding the subsequence's begin offset to them.
* Comparators of this type must be used with a {@link Subsequence}.
* Comparators of this type must be used with a
* {@link org.eclipse.jgit.diff.Subsequence}.
*
* @param <S>
* the base sequence type.
@ -67,11 +69,13 @@ public final class SubsequenceComparator<S extends Sequence> extends
this.cmp = cmp;
}
/** {@inheritDoc} */
@Override
public boolean equals(Subsequence<S> a, int ai, Subsequence<S> b, int bi) {
return cmp.equals(a.base, ai + a.begin, b.base, bi + b.begin);
}
/** {@inheritDoc} */
@Override
public int hash(Subsequence<S> seq, int ptr) {
return cmp.hash(seq.base, ptr + seq.begin);

Loading…
Cancel
Save