PortablePathOrder.java
package org.egothor.methodatlas.api;
import java.nio.file.Path;
import java.util.Comparator;
/**
* A total order on {@link Path} values that is identical on every operating
* system and file system.
*
* <p>
* {@link java.nio.file.Files#walk(Path, java.nio.file.FileVisitOption...)}
* returns entries in whatever order the file system yields them (hash order on
* ext4, alphabetical on NTFS, and so on), and {@link Path#compareTo(Path)} is
* case-insensitive on Windows but case-sensitive on Unix. Discovery plugins
* must emit methods in a machine-independent order so that scan output is
* byte-identical across machines, so they sort the files they find with this
* comparator.
* </p>
*
* <p>
* Paths are compared by their name elements joined with {@code '/'}, using
* {@link String#compareTo(String)} (UTF-16 code-unit order, no locale, no case
* folding). The comparator is meaningful for paths that share a common root,
* which is always the case for the files found under one scan root.
* </p>
*
* <p>
* Stateless and thread-safe.
* </p>
*/
public final class PortablePathOrder {
/** The shared comparator instance; never {@code null}. */
public static final Comparator<Path> INSTANCE = Comparator.comparing(PortablePathOrder::key);
private PortablePathOrder() {
// static holder; no instances
}
/**
* Builds the platform-independent sort key of a path.
*
* @param path the path; must not be {@code null}
* @return the name elements of {@code path} joined with {@code '/'}; the
* empty string for a path with no name elements
*/
/* default */ static String key(final Path path) {
final int count = path.getNameCount();
final StringBuilder sb = new StringBuilder(path.toString().length());
for (int i = 0; i < count; i++) {
if (i > 0) {
sb.append('/');
}
sb.append(path.getName(i));
}
return sb.toString();
}
}