/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.base.Function * com.google.common.base.Ticker * com.google.common.collect.ImmutableList * com.google.common.collect.ImmutableMap * com.google.common.collect.Iterators * com.google.common.collect.Lists * com.google.common.collect.Maps * com.google.common.util.concurrent.MoreExecutors * com.mojang.datafixers.DSL$TypeReference * com.mojang.datafixers.DataFixUtils * com.mojang.datafixers.Typed * com.mojang.datafixers.types.Type * com.mojang.datafixers.util.Pair * com.mojang.jtracy.TracyClient * com.mojang.jtracy.Zone * com.mojang.logging.LogUtils * com.mojang.serialization.DataResult * com.mojang.serialization.Dynamic * it.unimi.dsi.fastutil.ints.IntArrayList * it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap * it.unimi.dsi.fastutil.objects.ObjectArrayList * it.unimi.dsi.fastutil.objects.ObjectLists * it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap * it.unimi.dsi.fastutil.objects.ReferenceImmutableList * it.unimi.dsi.fastutil.objects.ReferenceList * org.jspecify.annotations.Nullable * org.slf4j.Logger */ package net.minecraft.util; import com.google.common.base.Function; import com.google.common.base.Ticker; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.util.concurrent.MoreExecutors; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.Typed; import com.mojang.datafixers.types.Type; import com.mojang.datafixers.util.Pair; import com.mojang.jtracy.TracyClient; import com.mojang.jtracy.Zone; import com.mojang.logging.LogUtils; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectLists; import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceImmutableList; import it.unimi.dsi.fastutil.objects.ReferenceList; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.CopyOption; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.spi.FileSystemProvider; import java.time.Duration; import java.time.Instant; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; import java.util.Arrays; import java.util.EnumMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionStage; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.function.ToIntFunction; import java.util.function.UnaryOperator; import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.LongStream; import java.util.stream.Stream; import net.minecraft.CharPredicate; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.DefaultUncaughtExceptionHandler; import net.minecraft.ReportType; import net.minecraft.ReportedException; import net.minecraft.SharedConstants; import net.minecraft.SuppressForbidden; import net.minecraft.TracingExecutor; import net.minecraft.core.Registry; import net.minecraft.resources.Identifier; import net.minecraft.server.Bootstrap; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.util.SingleKeyCache; import net.minecraft.util.TimeSource; import net.minecraft.util.datafix.DataFixers; import net.minecraft.world.level.block.state.properties.Property; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public class Util { private static final Logger LOGGER = LogUtils.getLogger(); private static final int DEFAULT_MAX_THREADS = 255; private static final int DEFAULT_SAFE_FILE_OPERATION_RETRIES = 10; private static final String MAX_THREADS_SYSTEM_PROPERTY = "max.bg.threads"; private static final TracingExecutor BACKGROUND_EXECUTOR = Util.makeExecutor("Main"); private static final TracingExecutor IO_POOL = Util.makeIoExecutor("IO-Worker-", false); private static final TracingExecutor DOWNLOAD_POOL = Util.makeIoExecutor("Download-", true); private static final DateTimeFormatter FILENAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT); public static final int LINEAR_LOOKUP_THRESHOLD = 8; private static final Set ALLOWED_UNTRUSTED_LINK_PROTOCOLS = Set.of("http", "https"); public static final long NANOS_PER_MILLI = 1000000L; public static TimeSource.NanoTimeSource timeSource = System::nanoTime; public static final Ticker TICKER = new Ticker(){ public long read() { return timeSource.getAsLong(); } }; public static final UUID NIL_UUID = new UUID(0L, 0L); public static final FileSystemProvider ZIP_FILE_SYSTEM_PROVIDER = FileSystemProvider.installedProviders().stream().filter(p -> p.getScheme().equalsIgnoreCase("jar")).findFirst().orElseThrow(() -> new IllegalStateException("No jar file system provider found")); private static Consumer thePauser = msg -> {}; public static Collector, ?, Map> toMap() { return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue); } public static Collector> toMutableList() { return Collectors.toCollection(Lists::newArrayList); } public static > String getPropertyName(Property key, Object value) { return key.getName((Comparable)value); } public static String makeDescriptionId(String prefix, @Nullable Identifier location) { if (location == null) { return prefix + ".unregistered_sadface"; } return prefix + "." + location.getNamespace() + "." + location.getPath().replace('/', '.'); } public static long getMillis() { return Util.getNanos() / 1000000L; } public static long getNanos() { return timeSource.getAsLong(); } public static long getEpochMillis() { return Instant.now().toEpochMilli(); } public static String getFilenameFormattedDateTime() { return FILENAME_DATE_TIME_FORMATTER.format(ZonedDateTime.now()); } private static TracingExecutor makeExecutor(final String name) { Object executor; int threads = Util.maxAllowedExecutorThreads(); if (threads <= 0) { executor = MoreExecutors.newDirectExecutorService(); } else { AtomicInteger workerCount = new AtomicInteger(1); executor = new ForkJoinPool(threads, pool -> { final String threadName = "Worker-" + name + "-" + workerCount.getAndIncrement(); ForkJoinWorkerThread thread = new ForkJoinWorkerThread(pool){ @Override protected void onStart() { TracyClient.setThreadName((String)threadName, (int)name.hashCode()); super.onStart(); } @Override protected void onTermination(@Nullable Throwable exception) { if (exception != null) { LOGGER.warn("{} died", (Object)this.getName(), (Object)exception); } else { LOGGER.debug("{} shutdown", (Object)this.getName()); } super.onTermination(exception); } }; thread.setName(threadName); return thread; }, Util::onThreadException, true); } return new TracingExecutor((ExecutorService)executor); } public static int maxAllowedExecutorThreads() { return Mth.clamp(Runtime.getRuntime().availableProcessors() - 1, 1, Util.getMaxThreads()); } private static int getMaxThreads() { String maxThreadsString = System.getProperty(MAX_THREADS_SYSTEM_PROPERTY); if (maxThreadsString != null) { try { int maxThreads = Integer.parseInt(maxThreadsString); if (maxThreads >= 1 && maxThreads <= 255) { return maxThreads; } LOGGER.error("Wrong {} property value '{}'. Should be an integer value between 1 and {}.", new Object[]{MAX_THREADS_SYSTEM_PROPERTY, maxThreadsString, 255}); } catch (NumberFormatException e) { LOGGER.error("Could not parse {} property value '{}'. Should be an integer value between 1 and {}.", new Object[]{MAX_THREADS_SYSTEM_PROPERTY, maxThreadsString, 255}); } } return 255; } public static TracingExecutor backgroundExecutor() { return BACKGROUND_EXECUTOR; } public static TracingExecutor ioPool() { return IO_POOL; } public static TracingExecutor nonCriticalIoPool() { return DOWNLOAD_POOL; } public static void shutdownExecutors() { BACKGROUND_EXECUTOR.shutdownAndAwait(3L, TimeUnit.SECONDS); IO_POOL.shutdownAndAwait(3L, TimeUnit.SECONDS); } private static TracingExecutor makeIoExecutor(String prefix, boolean daemon) { AtomicInteger workerCount = new AtomicInteger(1); return new TracingExecutor(Executors.newCachedThreadPool(runnable -> { Thread thread = new Thread(runnable); String name = prefix + workerCount.getAndIncrement(); TracyClient.setThreadName((String)name, (int)prefix.hashCode()); thread.setName(name); thread.setDaemon(daemon); thread.setUncaughtExceptionHandler(Util::onThreadException); return thread; })); } public static void throwAsRuntime(Throwable throwable) { throw throwable instanceof RuntimeException ? (RuntimeException)throwable : new RuntimeException(throwable); } private static void onThreadException(Thread thread, Throwable throwable) { Util.pauseInIde(throwable); if (throwable instanceof CompletionException) { throwable = throwable.getCause(); } if (throwable instanceof ReportedException) { ReportedException reportedException = (ReportedException)throwable; Bootstrap.realStdoutPrintln(reportedException.getReport().getFriendlyReport(ReportType.CRASH)); System.exit(-1); } LOGGER.error("Caught exception in thread {}", (Object)thread, (Object)throwable); } public static @Nullable Type fetchChoiceType(DSL.TypeReference reference, String name) { if (!SharedConstants.CHECK_DATA_FIXER_SCHEMA) { return null; } return Util.doFetchChoiceType(reference, name); } private static @Nullable Type doFetchChoiceType(DSL.TypeReference reference, String name) { Type dataType; block2: { dataType = null; try { dataType = DataFixers.getDataFixer().getSchema(DataFixUtils.makeKey((int)SharedConstants.getCurrentVersion().dataVersion().version())).getChoiceType(reference, name); } catch (IllegalArgumentException e) { LOGGER.error("No data fixer registered for {}", (Object)name); if (!SharedConstants.IS_RUNNING_IN_IDE) break block2; throw e; } } return dataType; } /* * WARNING - Removed try catching itself - possible behaviour change. */ public static void runNamed(Runnable runnable, String name) { block16: { if (SharedConstants.IS_RUNNING_IN_IDE) { Thread thread = Thread.currentThread(); String oldName = thread.getName(); thread.setName(name); try (Zone ignored = TracyClient.beginZone((String)name, (boolean)SharedConstants.IS_RUNNING_IN_IDE);){ runnable.run(); break block16; } finally { thread.setName(oldName); } } try (Zone ignored = TracyClient.beginZone((String)name, (boolean)SharedConstants.IS_RUNNING_IN_IDE);){ runnable.run(); } } } public static String getRegisteredName(Registry registry, T entry) { Identifier key = registry.getKey(entry); if (key == null) { return "[unregistered]"; } return key.toString(); } public static Predicate allOf() { return context -> true; } public static Predicate allOf(Predicate condition) { return condition; } public static Predicate allOf(Predicate condition1, Predicate condition2) { return context -> condition1.test(context) && condition2.test(context); } public static Predicate allOf(Predicate condition1, Predicate condition2, Predicate condition3) { return context -> condition1.test(context) && condition2.test(context) && condition3.test(context); } public static Predicate allOf(Predicate condition1, Predicate condition2, Predicate condition3, Predicate condition4) { return context -> condition1.test(context) && condition2.test(context) && condition3.test(context) && condition4.test(context); } public static Predicate allOf(Predicate condition1, Predicate condition2, Predicate condition3, Predicate condition4, Predicate condition5) { return context -> condition1.test(context) && condition2.test(context) && condition3.test(context) && condition4.test(context) && condition5.test(context); } @SafeVarargs public static Predicate allOf(Predicate ... conditions) { return context -> { for (Predicate entry : conditions) { if (entry.test(context)) continue; return false; } return true; }; } public static Predicate allOf(List> conditions) { return switch (conditions.size()) { case 0 -> Util.allOf(); case 1 -> Util.allOf(conditions.get(0)); case 2 -> Util.allOf(conditions.get(0), conditions.get(1)); case 3 -> Util.allOf(conditions.get(0), conditions.get(1), conditions.get(2)); case 4 -> Util.allOf(conditions.get(0), conditions.get(1), conditions.get(2), conditions.get(3)); case 5 -> Util.allOf(conditions.get(0), conditions.get(1), conditions.get(2), conditions.get(3), conditions.get(4)); default -> { Predicate[] conditionsCopy = (Predicate[])conditions.toArray(Predicate[]::new); yield Util.allOf(conditionsCopy); } }; } public static Predicate anyOf() { return context -> false; } public static Predicate anyOf(Predicate condition1) { return condition1; } public static Predicate anyOf(Predicate condition1, Predicate condition2) { return context -> condition1.test(context) || condition2.test(context); } public static Predicate anyOf(Predicate condition1, Predicate condition2, Predicate condition3) { return context -> condition1.test(context) || condition2.test(context) || condition3.test(context); } public static Predicate anyOf(Predicate condition1, Predicate condition2, Predicate condition3, Predicate condition4) { return context -> condition1.test(context) || condition2.test(context) || condition3.test(context) || condition4.test(context); } public static Predicate anyOf(Predicate condition1, Predicate condition2, Predicate condition3, Predicate condition4, Predicate condition5) { return context -> condition1.test(context) || condition2.test(context) || condition3.test(context) || condition4.test(context) || condition5.test(context); } @SafeVarargs public static Predicate anyOf(Predicate ... conditions) { return context -> { for (Predicate entry : conditions) { if (!entry.test(context)) continue; return true; } return false; }; } public static Predicate anyOf(List> conditions) { return switch (conditions.size()) { case 0 -> Util.anyOf(); case 1 -> Util.anyOf(conditions.get(0)); case 2 -> Util.anyOf(conditions.get(0), conditions.get(1)); case 3 -> Util.anyOf(conditions.get(0), conditions.get(1), conditions.get(2)); case 4 -> Util.anyOf(conditions.get(0), conditions.get(1), conditions.get(2), conditions.get(3)); case 5 -> Util.anyOf(conditions.get(0), conditions.get(1), conditions.get(2), conditions.get(3), conditions.get(4)); default -> { Predicate[] conditionsCopy = (Predicate[])conditions.toArray(Predicate[]::new); yield Util.anyOf(conditionsCopy); } }; } public static boolean isSymmetrical(int width, int height, List ingredients) { if (width == 1) { return true; } int centerX = width / 2; for (int y = 0; y < height; ++y) { for (int leftX = 0; leftX < centerX; ++leftX) { T right; int rightX = width - 1 - leftX; T left = ingredients.get(leftX + y * width); if (left.equals(right = ingredients.get(rightX + y * width))) continue; return false; } } return true; } public static int growByHalf(int currentSize, int minimalNewSize) { return (int)Math.max(Math.min((long)currentSize + (long)(currentSize >> 1), 0x7FFFFFF7L), (long)minimalNewSize); } @SuppressForbidden(reason="Intentional use of default locale for user-visible date") public static DateTimeFormatter localizedDateFormatter(FormatStyle formatStyle) { return DateTimeFormatter.ofLocalizedDateTime(formatStyle); } public static OS getPlatform() { String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT); if (osName.contains("win")) { return OS.WINDOWS; } if (osName.contains("mac")) { return OS.OSX; } if (osName.contains("solaris")) { return OS.SOLARIS; } if (osName.contains("sunos")) { return OS.SOLARIS; } if (osName.contains("linux")) { return OS.LINUX; } if (osName.contains("unix")) { return OS.LINUX; } return OS.UNKNOWN; } public static boolean isAarch64() { String arch = System.getProperty("os.arch").toLowerCase(Locale.ROOT); return arch.equals("aarch64"); } public static URI parseAndValidateUntrustedUri(String uri) throws URISyntaxException { URI parsedUri = new URI(uri); String scheme = parsedUri.getScheme(); if (scheme == null) { throw new URISyntaxException(uri, "Missing protocol in URI: " + uri); } String protocol = scheme.toLowerCase(Locale.ROOT); if (!ALLOWED_UNTRUSTED_LINK_PROTOCOLS.contains(protocol)) { throw new URISyntaxException(uri, "Unsupported protocol in URI: " + uri); } return parsedUri; } public static T findNextInIterable(Iterable collection, @Nullable T current) { Iterator iterator = collection.iterator(); T first = iterator.next(); if (current != null) { T property = first; while (true) { if (property == current) { if (!iterator.hasNext()) break; return iterator.next(); } if (!iterator.hasNext()) continue; property = iterator.next(); } } return first; } public static T findPreviousInIterable(Iterable collection, @Nullable T current) { Iterator iterator = collection.iterator(); T last = null; while (iterator.hasNext()) { T next = iterator.next(); if (next == current) { if (last != null) break; last = (T)(iterator.hasNext() ? Iterators.getLast(iterator) : current); break; } last = next; } return last; } public static T make(Supplier factory) { return factory.get(); } public static T make(T t, Consumer consumer) { consumer.accept(t); return t; } public static , V> Map makeEnumMap(Class keyType, java.util.function.Function function) { EnumMap map = new EnumMap(keyType); for (Enum key : (Enum[])keyType.getEnumConstants()) { map.put(key, function.apply(key)); } return map; } public static Map mapValues(Map map, java.util.function.Function valueMapper) { return map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> valueMapper.apply((Object)e.getValue()))); } public static Map mapValuesLazy(Map map, Function valueMapper) { return Maps.transformValues(map, valueMapper); } public static CompletableFuture> sequence(List> futures) { if (futures.isEmpty()) { return CompletableFuture.completedFuture(List.of()); } if (futures.size() == 1) { return futures.getFirst().thenApply(ObjectLists::singleton); } CompletableFuture all = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); return all.thenApply(ignored -> futures.stream().map(CompletableFuture::join).toList()); } public static CompletableFuture> sequenceFailFast(List> futures) { CompletableFuture failureFuture = new CompletableFuture(); return Util.fallibleSequence(futures, failureFuture::completeExceptionally).applyToEither((CompletionStage)failureFuture, java.util.function.Function.identity()); } public static CompletableFuture> sequenceFailFastAndCancel(List> futures) { CompletableFuture failureFuture = new CompletableFuture(); return Util.fallibleSequence(futures, exception -> { if (failureFuture.completeExceptionally((Throwable)exception)) { for (CompletableFuture future : futures) { future.cancel(true); } } }).applyToEither((CompletionStage)failureFuture, java.util.function.Function.identity()); } private static CompletableFuture> fallibleSequence(List> futures, Consumer failureHandler) { ObjectArrayList results = new ObjectArrayList(); results.size(futures.size()); CompletableFuture[] decoratedFutures = new CompletableFuture[futures.size()]; for (int i = 0; i < futures.size(); ++i) { int index = i; decoratedFutures[i] = futures.get(i).whenComplete((result, exception) -> { if (exception != null) { failureHandler.accept((Throwable)exception); } else { results.set(index, result); } }); } return CompletableFuture.allOf(decoratedFutures).thenApply(nothing -> results); } public static Optional ifElse(Optional input, Consumer onTrue, Runnable onFalse) { if (input.isPresent()) { onTrue.accept(input.get()); } else { onFalse.run(); } return input; } public static Supplier name(final Supplier task, Supplier nameGetter) { if (SharedConstants.DEBUG_NAMED_RUNNABLES) { final String name = nameGetter.get(); return new Supplier(){ @Override public T get() { return task.get(); } public String toString() { return name; } }; } return task; } public static Runnable name(final Runnable task, Supplier nameGetter) { if (SharedConstants.DEBUG_NAMED_RUNNABLES) { final String name = nameGetter.get(); return new Runnable(){ @Override public void run() { task.run(); } public String toString() { return name; } }; } return task; } public static void logAndPauseIfInIde(String message) { LOGGER.error(message); if (SharedConstants.IS_RUNNING_IN_IDE) { Util.doPause(message); } } public static void logAndPauseIfInIde(String message, Throwable throwable) { LOGGER.error(message, throwable); if (SharedConstants.IS_RUNNING_IN_IDE) { Util.doPause(message); } } public static T pauseInIde(T t) { if (SharedConstants.IS_RUNNING_IN_IDE) { LOGGER.error("Trying to throw a fatal exception, pausing in IDE", t); Util.doPause(t.getMessage()); } return t; } public static void setPause(Consumer pauseFunction) { thePauser = pauseFunction; } private static void doPause(String message) { boolean dontBotherWithPause; Instant preLog = Instant.now(); LOGGER.warn("Did you remember to set a breakpoint here?"); boolean bl = dontBotherWithPause = Duration.between(preLog, Instant.now()).toMillis() > 500L; if (!dontBotherWithPause) { thePauser.accept(message); } } public static String describeError(Throwable err) { if (err.getCause() != null) { return Util.describeError(err.getCause()); } if (err.getMessage() != null) { return err.getMessage(); } return err.toString(); } public static T getRandom(T[] array, RandomSource random) { return array[random.nextInt(array.length)]; } public static int getRandom(int[] array, RandomSource random) { return array[random.nextInt(array.length)]; } public static T getRandom(List list, RandomSource random) { return list.get(random.nextInt(list.size())); } public static Optional getRandomSafe(List list, RandomSource random) { if (list.isEmpty()) { return Optional.empty(); } return Optional.of(Util.getRandom(list, random)); } private static BooleanSupplier createRenamer(final Path from, final Path to) { return new BooleanSupplier(){ @Override public boolean getAsBoolean() { try { Files.move(from, to, new CopyOption[0]); return true; } catch (IOException e) { LOGGER.error("Failed to rename", (Throwable)e); return false; } } public String toString() { return "rename " + String.valueOf(from) + " to " + String.valueOf(to); } }; } private static BooleanSupplier createDeleter(final Path target) { return new BooleanSupplier(){ @Override public boolean getAsBoolean() { try { Files.deleteIfExists(target); return true; } catch (IOException e) { LOGGER.warn("Failed to delete", (Throwable)e); return false; } } public String toString() { return "delete old " + String.valueOf(target); } }; } private static BooleanSupplier createFileDeletedCheck(final Path target) { return new BooleanSupplier(){ @Override public boolean getAsBoolean() { return !Files.exists(target, new LinkOption[0]); } public String toString() { return "verify that " + String.valueOf(target) + " is deleted"; } }; } private static BooleanSupplier createFileCreatedCheck(final Path target) { return new BooleanSupplier(){ @Override public boolean getAsBoolean() { return Files.isRegularFile(target, new LinkOption[0]); } public String toString() { return "verify that " + String.valueOf(target) + " is present"; } }; } private static boolean executeInSequence(BooleanSupplier ... operations) { for (BooleanSupplier operation : operations) { if (operation.getAsBoolean()) continue; LOGGER.warn("Failed to execute {}", (Object)operation); return false; } return true; } private static boolean runWithRetries(int numberOfRetries, String description, BooleanSupplier ... operations) { for (int retry = 0; retry < numberOfRetries; ++retry) { if (Util.executeInSequence(operations)) { return true; } LOGGER.error("Failed to {}, retrying {}/{}", new Object[]{description, retry, numberOfRetries}); } LOGGER.error("Failed to {}, aborting, progress might be lost", (Object)description); return false; } public static void safeReplaceFile(Path targetPath, Path newPath, Path backupPath) { Util.safeReplaceOrMoveFile(targetPath, newPath, backupPath, false); } public static boolean safeReplaceOrMoveFile(Path targetPath, Path newPath, Path backupPath, boolean noRollback) { if (Files.exists(targetPath, new LinkOption[0]) && !Util.runWithRetries(10, "create backup " + String.valueOf(backupPath), Util.createDeleter(backupPath), Util.createRenamer(targetPath, backupPath), Util.createFileCreatedCheck(backupPath))) { return false; } if (!Util.runWithRetries(10, "remove old " + String.valueOf(targetPath), Util.createDeleter(targetPath), Util.createFileDeletedCheck(targetPath))) { return false; } if (!Util.runWithRetries(10, "replace " + String.valueOf(targetPath) + " with " + String.valueOf(newPath), Util.createRenamer(newPath, targetPath), Util.createFileCreatedCheck(targetPath)) && !noRollback) { Util.runWithRetries(10, "restore " + String.valueOf(targetPath) + " from " + String.valueOf(backupPath), Util.createRenamer(backupPath, targetPath), Util.createFileCreatedCheck(targetPath)); return false; } return true; } public static int offsetByCodepoints(String input, int pos, int offset) { int length = input.length(); if (offset >= 0) { for (int i = 0; pos < length && i < offset; ++i) { if (!Character.isHighSurrogate(input.charAt(pos++)) || pos >= length || !Character.isLowSurrogate(input.charAt(pos))) continue; ++pos; } } else { for (int i = offset; pos > 0 && i < 0; ++i) { if (!Character.isLowSurrogate(input.charAt(--pos)) || pos <= 0 || !Character.isHighSurrogate(input.charAt(pos - 1))) continue; --pos; } } return pos; } public static Consumer prefix(String prefix, Consumer consumer) { return s -> consumer.accept(prefix + s); } public static DataResult fixedSize(IntStream stream, int size) { int[] ints = stream.limit(size + 1).toArray(); if (ints.length != size) { Supplier message = () -> "Input is not a list of " + size + " ints"; if (ints.length >= size) { return DataResult.error(message, (Object)Arrays.copyOf(ints, size)); } return DataResult.error(message); } return DataResult.success((Object)ints); } public static DataResult fixedSize(LongStream stream, int size) { long[] longs = stream.limit(size + 1).toArray(); if (longs.length != size) { Supplier message = () -> "Input is not a list of " + size + " longs"; if (longs.length >= size) { return DataResult.error(message, (Object)Arrays.copyOf(longs, size)); } return DataResult.error(message); } return DataResult.success((Object)longs); } public static DataResult> fixedSize(List list, int size) { if (list.size() != size) { Supplier message = () -> "Input is not a list of " + size + " elements"; if (list.size() >= size) { return DataResult.error(message, list.subList(0, size)); } return DataResult.error(message); } return DataResult.success(list); } public static void startTimerHackThread() { Thread timerThread = new Thread("Timer hack thread"){ @Override public void run() { try { while (true) { Thread.sleep(Integer.MAX_VALUE); } } catch (InterruptedException e) { LOGGER.warn("Timer hack thread interrupted, that really should not happen"); return; } } }; timerThread.setDaemon(true); timerThread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)); timerThread.start(); } public static void copyBetweenDirs(Path sourceDir, Path targetDir, Path sourcePath) throws IOException { Path relative = sourceDir.relativize(sourcePath); Path target = targetDir.resolve(relative); Files.copy(sourcePath, target, new CopyOption[0]); } public static String sanitizeName(String value, CharPredicate isAllowedChar) { return value.toLowerCase(Locale.ROOT).chars().mapToObj(c -> isAllowedChar.test((char)c) ? Character.toString((char)c) : "_").collect(Collectors.joining()); } public static SingleKeyCache singleKeyCache(java.util.function.Function computeValueFunction) { return new SingleKeyCache(computeValueFunction); } public static java.util.function.Function memoize(final java.util.function.Function function) { return new java.util.function.Function(){ private final Map cache = new ConcurrentHashMap(); @Override public R apply(T arg) { return this.cache.computeIfAbsent(arg, function); } public String toString() { return "memoize/1[function=" + String.valueOf(function) + ", size=" + this.cache.size() + "]"; } }; } public static BiFunction memoize(final BiFunction function) { return new BiFunction(){ private final Map, R> cache = new ConcurrentHashMap(); @Override public R apply(T a, U b) { return this.cache.computeIfAbsent(Pair.of(a, b), args -> function.apply(args.getFirst(), args.getSecond())); } public String toString() { return "memoize/2[function=" + String.valueOf(function) + ", size=" + this.cache.size() + "]"; } }; } public static List toShuffledList(Stream stream, RandomSource random) { ObjectArrayList result = (ObjectArrayList)stream.collect(ObjectArrayList.toList()); Util.shuffle(result, random); return result; } public static IntArrayList toShuffledList(IntStream stream, RandomSource random) { int size; IntArrayList result = IntArrayList.wrap((int[])stream.toArray()); for (int i = size = result.size(); i > 1; --i) { int swapTo = random.nextInt(i); result.set(i - 1, result.set(swapTo, result.getInt(i - 1))); } return result; } public static List shuffledCopy(T[] array, RandomSource random) { ObjectArrayList copy = new ObjectArrayList((Object[])array); Util.shuffle(copy, random); return copy; } public static List shuffledCopy(ObjectArrayList list, RandomSource random) { ObjectArrayList copy = new ObjectArrayList(list); Util.shuffle(copy, random); return copy; } public static void shuffle(List list, RandomSource random) { int size; for (int i = size = list.size(); i > 1; --i) { int swapTo = random.nextInt(i); list.set(i - 1, list.set(swapTo, list.get(i - 1))); } } public static CompletableFuture blockUntilDone(java.util.function.Function> task) { return Util.blockUntilDone(task, CompletableFuture::isDone); } public static T blockUntilDone(java.util.function.Function task, Predicate completionCheck) { int remainingSize; LinkedBlockingQueue tasks = new LinkedBlockingQueue(); T result = task.apply(tasks::add); while (!completionCheck.test(result)) { try { Runnable runnable = (Runnable)tasks.poll(100L, TimeUnit.MILLISECONDS); if (runnable == null) continue; runnable.run(); } catch (InterruptedException e) { LOGGER.warn("Interrupted wait"); break; } } if ((remainingSize = tasks.size()) > 0) { LOGGER.warn("Tasks left in queue: {}", (Object)remainingSize); } return result; } public static ToIntFunction createIndexLookup(List values) { int size = values.size(); if (size < 8) { return values::indexOf; } Object2IntOpenHashMap lookup = new Object2IntOpenHashMap(size); lookup.defaultReturnValue(-1); for (int i = 0; i < size; ++i) { lookup.put(values.get(i), i); } return lookup; } public static ToIntFunction createIndexIdentityLookup(List values) { int size = values.size(); if (size < 8) { ReferenceImmutableList referenceLookup = new ReferenceImmutableList(values); return arg_0 -> ((ReferenceList)referenceLookup).indexOf(arg_0); } Reference2IntOpenHashMap lookup = new Reference2IntOpenHashMap(size); lookup.defaultReturnValue(-1); for (int i = 0; i < size; ++i) { lookup.put(values.get(i), i); } return lookup; } public static Typed writeAndReadTypedOrThrow(Typed typed, Type newType, UnaryOperator> function) { Dynamic dynamic = (Dynamic)typed.write().getOrThrow(); return Util.readTypedOrThrow(newType, (Dynamic)function.apply(dynamic), true); } public static Typed readTypedOrThrow(Type type, Dynamic dynamic) { return Util.readTypedOrThrow(type, dynamic, false); } public static Typed readTypedOrThrow(Type type, Dynamic dynamic, boolean acceptPartial) { DataResult result = type.readTyped(dynamic).map(Pair::getFirst); try { if (acceptPartial) { return (Typed)result.getPartialOrThrow(IllegalStateException::new); } return (Typed)result.getOrThrow(IllegalStateException::new); } catch (IllegalStateException e) { CrashReport report = CrashReport.forThrowable(e, "Reading type"); CrashReportCategory category = report.addCategory("Info"); category.setDetail("Data", dynamic); category.setDetail("Type", type); throw new ReportedException(report); } } public static List copyAndAdd(List list, T element) { return ImmutableList.builderWithExpectedSize((int)(list.size() + 1)).addAll(list).add(element).build(); } public static List copyAndAdd(T element, List list) { return ImmutableList.builderWithExpectedSize((int)(list.size() + 1)).add(element).addAll(list).build(); } public static Map copyAndPut(Map map, K key, V value) { return ImmutableMap.builderWithExpectedSize((int)(map.size() + 1)).putAll(map).put(key, value).buildKeepingLast(); } public static enum OS { LINUX("linux"), SOLARIS("solaris"), WINDOWS("windows"){ @Override protected String[] getOpenUriArguments(URI uri) { return new String[]{"rundll32", "url.dll,FileProtocolHandler", uri.toString()}; } } , OSX("mac"){ @Override protected String[] getOpenUriArguments(URI uri) { return new String[]{"open", uri.toString()}; } } , UNKNOWN("unknown"); private final String telemetryName; private OS(String telemetryName) { this.telemetryName = telemetryName; } public void openUri(URI uri) { try { Process process = Runtime.getRuntime().exec(this.getOpenUriArguments(uri)); process.getInputStream().close(); process.getErrorStream().close(); process.getOutputStream().close(); } catch (IOException e) { LOGGER.error("Couldn't open location '{}'", (Object)uri, (Object)e); } } public void openFile(File file) { this.openUri(file.toURI()); } public void openPath(Path path) { this.openUri(path.toUri()); } protected String[] getOpenUriArguments(URI uri) { String string = uri.toString(); if ("file".equals(uri.getScheme())) { string = string.replace("file:", "file://"); } return new String[]{"xdg-open", string}; } public void openUri(String uri) { try { this.openUri(new URI(uri)); } catch (IllegalArgumentException | URISyntaxException e) { LOGGER.error("Couldn't open uri '{}'", (Object)uri, (Object)e); } } public String telemetryName() { return this.telemetryName; } } }