diff --git a/CREDITS b/CREDITS index e2987d11..7114371a 100644 --- a/CREDITS +++ b/CREDITS @@ -6,21 +6,20 @@ - Creator of Eaglercraft - Ported the Minecraft 1.8 src to TeaVM - - Wrote HW accelerated OpenGL 1.3 emulator - - Wrote the default shader pack + - Optimized the Minecraft 1.8 src + - Made the platform abstraction layer + - Made HW accelerated OpenGL 1.3 emulator + - Made the default shader pack - Made the integrated PBR resource pack - Added touch and mobile device support - - Wrote all desktop emulation code - - Wrote EaglercraftXBungee - - Wrote EaglercraftXVelocity - - Wrote WebRTC relay server - - Wrote voice chat server - - Wrote the patch and build system + - Made the multiplayer backends + - Made the shared world relay server + - Made the patch and build system ayunami2000: - Many bug fixes - - WebRTC LAN worlds + - WebRTC shared worlds - WebRTC voice chat - Worked on touch support - Made velocity plugin work @@ -29,6 +28,11 @@ - Added seamless fullscreen - Created the replit + cire3: + + - Created the Gradle plugin + - Proponent of Kotlin DSL + Code used within EaglercraftX diff --git a/README.md b/README.md index f63e92f5..00e3e530 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,9 @@ The JavaScript runtime of EaglercraftX 1.8 is currently known to work on browser ## WebAssembly GC Support -EaglercraftX 1.8 also has an experimental WebAssembly GC (WASM-GC) runtime, almost all of the features supported on the JavaScript runtime are also supported on the WebAssembly GC runtime, however it is still incompatible with several major browsers (especially Safari) and will not run in Chrome unless you can access the `chrome://flags` menu or request an origin trial token from Google for your website. Its based on experimental technology and may still crash sometimes due to browser bugs or unresolved issues in the Java to WASM compiler. Hopefully in the coming months the required feature (JSPI, WebAssembly JavaScript Promise Integration) will become enabled by default on the Chrome browser. It performs significantly better than the JavaScript client, around 50% more FPS and TPS in some cases, and will hopefully replace it someday. Just make sure you enable VSync when you play it, otherwise the game will run "too fast" and choke the browser's event loop, causing input lag. +EaglercraftX 1.8 also has an experimental WebAssembly GC (WASM-GC) runtime, almost all of the features supported on the JavaScript runtime are also supported on the WebAssembly GC runtime, however it is still incompatible with several major browsers (especially Safari) and will not run in Chrome unless you can access the `chrome://flags` menu or request an origin trial token from Google for your website. Its based on experimental technology and may still crash sometimes, mostly due to browser bugs. Hopefully in the coming months the required feature (JSPI, WebAssembly JavaScript Promise Integration) will become enabled by default on the Chrome browser. It performs significantly better than the JavaScript client, around 50% more FPS and TPS in some cases, and will hopefully replace it someday. Just make sure you enable VSync when you play it, otherwise the game will run "too fast" and choke the browser's event loop, causing input lag. -You can compile the WebAssembly GC runtime by creating a development environment (workspace) and reading the README in the "wasm_gc_teavm" folder. +There is no GUI for compiling the WASM-GC client at the moment, you need to compile it using the `MakeWASMClientBundle` script in the development environment. ## Singleplayer @@ -208,5 +208,3 @@ The `crashReportShow` hook can be used to capture crash reports and append addit ## Developing a Client There is currently no system in place to make forks of 1.8 and merge commits made to the patch files in this repository with the patch files or workspace of the fork, you're on your own if you try to keep a fork of this repo for reasons other than to contribute to it - -**Note:** If you are trying to use the desktop runtime on Linux, make sure you add the "desktopRuntime" folder to the `LD_LIBRARY_PATH` environment variable of the Java process. This should be done automatically by the Eclipse project's default run configuration, but it might not work properly on every system, or when the Eclipse project is imported into IntelliJ. diff --git a/buildtools/BuildTools.jar b/buildtools/BuildTools.jar index 9c5a3b59..697b34e6 100644 Binary files a/buildtools/BuildTools.jar and b/buildtools/BuildTools.jar differ diff --git a/buildtools/Java17Check.jar b/buildtools/Java17Check.jar new file mode 100644 index 00000000..9485aa7d Binary files /dev/null and b/buildtools/Java17Check.jar differ diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientFrame.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientFrame.java index 747ab74a..b1a61a5e 100644 --- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientFrame.java +++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientFrame.java @@ -471,7 +471,7 @@ public class CompileLatestClientFrame { txtpnfuckOffwelcome.setEditable(false); txtpnfuckOffwelcome.setMargin(new Insets(10, 10, 10, 10)); txtpnfuckOffwelcome.setContentType("text/html"); - txtpnfuckOffwelcome.setText("\r\nfuck off\r\n\r\n

Welcome to the EaglercraftX 1.8 Client Compiler

\r\n

This tool will allow you to automatically compile the latest version of the EaglercraftX 1.8 client using the files in this repository.

\r\n

You are required to download several required files manually in order to better respect the Microsoft/Mojang TOS. The links to these files will be provided.

\r\n

To view or modify portions of the EaglercraftX 1.8 source code directly, please use the other batch files to generate a gradle project instead of compiling the javascript files directly

\r\n

If you are from Microsoft/Mojang or the developer of MCP trying to get dirt on me, please just let me live my life, the repository does not contain your intellectual property. Using this code to play your game for free is not the default behavior of the gateway plugin or this compiler utility and is not encouraged by the documentation

\r\n\r\n"); + txtpnfuckOffwelcome.setText("\r\nfuck off\r\n\r\n

Welcome to the EaglercraftX 1.8 Client Compiler

\r\n

This tool will allow you to automatically compile the latest version of the EaglercraftX 1.8 client using the files in this repository.

\r\n

You are required to download several required files manually in order to better respect the Microsoft/Mojang TOS. The links to these files will be provided.

\r\n

To view or modify portions of the EaglercraftX 1.8 source code directly, please use the other batch files to generate a gradle project instead of compiling the javascript files directly

\r\n

This tool will only build the JavaScript client, to build WASM-GC please create a workspace and use the Gradle project to build it instead.

\r\n\r\n"); pageHome.add(txtpnfuckOffwelcome, BorderLayout.CENTER); JPanel pageLicense = new JPanel(); diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientGUI.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientGUI.java index b5693694..110426fa 100644 --- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientGUI.java +++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientGUI.java @@ -66,16 +66,16 @@ public class CompileLatestClientGUI { | UnsupportedLookAndFeelException e) { System.err.println("Could not set system look and feel: " + e.toString()); } - if(!System.getProperty("eaglercraft.isJava11", "false").equalsIgnoreCase("true")) { + if(!System.getProperty("eaglercraft.isJava17", "false").equalsIgnoreCase("true")) { try { if (!(boolean) Class - .forName("net.lax1dude.eaglercraft.v1_8.buildtools.Java11Check", true, - new URLClassLoader(new URL[] { (new File("buildtools/Java11Check.jar")).toURI().toURL() })) + .forName("net.lax1dude.eaglercraft.v1_8.buildtools.Java17Check", true, + new URLClassLoader(new URL[] { (new File("buildtools/Java17Check.jar")).toURI().toURL() })) .getMethod("classLoadCheck").invoke(null)) { throw new RuntimeException("wtf?"); } }catch(Throwable t) { - JOptionPane.showMessageDialog(null, "Error: Java 11 is required to run this program", "Unsupported JRE", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, "Error: Java 17 is required to run this program", "Unsupported JRE", JOptionPane.ERROR_MESSAGE); System.exit(-1); return; } @@ -90,7 +90,7 @@ public class CompileLatestClientGUI { System.setErr(new PrintStream(new ConsoleRedirector(true))); if(JavaC.jdkHome == null) { if(JOptionPane.showConfirmDialog(frame.frmCompileLatestClient, "Error: A JDK is required to run this program!\nYou are currently running on a JRE\nDo you have a JDK installed that you would like to use instead?", "Unsupported JRE", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "You need at least JDK 8 to compile EaglercraftX 1.8!\nSelect the path to the installation you want to use", "Unsupported JRE", JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "You need at least JDK 17 to compile EaglercraftX 1.8!\nSelect the path to the installation you want to use", "Unsupported JRE", JOptionPane.INFORMATION_MESSAGE); JFileChooser fileChooser = new JFileChooser((new File(System.getProperty("java.home"))).getParentFile()); fileChooser.setMultiSelectionEnabled(false); fileChooser.setFileHidingEnabled(false); @@ -106,7 +106,7 @@ public class CompileLatestClientGUI { } } } - JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "Please install JDK 8 or newer to continue", "Unsupported JRE", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "Please install JDK 17 or newer to continue", "Unsupported JRE", JOptionPane.ERROR_MESSAGE); System.exit(-1); return; } @@ -256,6 +256,7 @@ public class CompileLatestClientGUI { new File(repositoryFolder, "sources/protocol-game/java"), new File(repositoryFolder, "sources/protocol-relay/java"), new File(repositoryFolder, "sources/teavm/java"), + new File(repositoryFolder, "sources/teavm/resources"), new File(repositoryFolder, "sources/teavm-boot-menu/java")); }catch(IOException ex) { throw new CompileFailureException("failed to run javac compiler! " + ex.toString(), ex); @@ -331,11 +332,11 @@ public class CompileLatestClientGUI { File classesJS = new File(outputDirectory, "classes.js"); - if(!ES6Compat.patchClassesJS(classesJS, new File(repositoryFolder, "sources/setup/workspace_template/javascript/ES6ShimScript.txt"))) { + if(!ES6Compat.patchClassesJS(classesJS, new File(repositoryFolder, "sources/setup/workspace_template/target_teavm_javascript/javascript/ES6ShimScript.txt"))) { System.err.println("Error: could not inject shim, continuing anyway because it is not required"); } - File epkCompiler = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/CompileEPK.jar"); + File epkCompiler = new File(repositoryFolder, "sources/setup/workspace_template/target_teavm_javascript/buildtools/CompileEPK.jar"); if(!epkCompiler.exists()) { throw new CompileFailureException("EPKCompiler JAR file is missing: " + epkCompiler.getAbsolutePath()); @@ -390,9 +391,9 @@ public class CompileLatestClientGUI { if(generateOfflineDownload) { System.out.println("Running offline download generator..."); System.out.println(); - File offlineDownloadGenerator = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/MakeOfflineDownload.jar"); + File offlineDownloadGenerator = new File(repositoryFolder, "sources/setup/workspace_template/target_teavm_javascript/buildtools/MakeOfflineDownload.jar"); MakeOfflineDownload.compilerMain(offlineDownloadGenerator, new String[] { - (new File(repositoryFolder, "sources/setup/workspace_template/javascript/OfflineDownloadTemplate.txt")).getAbsolutePath(), + (new File(repositoryFolder, "sources/setup/workspace_template/target_teavm_javascript/javascript/OfflineDownloadTemplate.txt")).getAbsolutePath(), classesJS.getAbsolutePath(), (new File(outputDirectory, "assets.epk")).getAbsolutePath(), (new File(outputDirectory, "EaglercraftX_1.8_Offline_en_US.html")).getAbsolutePath(), (new File(outputDirectory, "EaglercraftX_1.8_Offline_International.html")).getAbsolutePath(), diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/JavaC.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/JavaC.java index 9a74027b..9292ec35 100644 --- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/JavaC.java +++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/JavaC.java @@ -37,7 +37,7 @@ public class JavaC { public static final List compilerFlags = Arrays.asList( "-Xlint:-unchecked", "-Xlint:-options", "-Xlint:-deprecation", - "-source", "1.8", "-target", "1.8", "-encoding", "utf8" + "-source", "17", "-target", "17", "-encoding", "utf8" ); private static int debugSourceFileCount = 0; diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/TeaVMBinaries.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/TeaVMBinaries.java index ca958aee..0e3a1704 100644 --- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/TeaVMBinaries.java +++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/TeaVMBinaries.java @@ -62,12 +62,16 @@ public class TeaVMBinaries { public static final MavenJAREntry teavmMetaprogrammingImpl = new MavenJAREntry("org/teavm/teavm-metaprogramming-impl/0.9.2/teavm-metaprogramming-impl-0.9.2.jar"); public static final MavenJAREntry teavmJodaTime = new MavenJAREntry("joda-time/joda-time/2.12.2/joda-time-2.12.2.jar"); public static final MavenJAREntry teavmJZLIB = new MavenJAREntry("com/jcraft/jzlib/1.1.3/jzlib-1.1.3.jar"); + public static final MavenJAREntry depJOrbis = new MavenJAREntry("org/jcraft/jorbis/0.0.17/jorbis-0.0.17.jar"); + public static final MavenJAREntry depLang3 = new MavenJAREntry("org/apache/commons/commons-lang3/3.6/commons-lang3-3.6.jar"); + public static final MavenJAREntry depHPPC = new MavenJAREntry("com/carrotsearch/hppc/0.10.0/hppc-0.10.0.jar"); + public static final MavenJAREntry depJSR305 = new MavenJAREntry("com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar"); private static final MavenJAREntry[] jarsList = new MavenJAREntry[] { teavmCore, teavmCli, teavmTooling, teavmPlatform, teavmClasslib, teavmInterop, teavmJSO, teavmJSOApis, teavmJSOImpl, teavmRelocatedLibsASM, teavmRelocatedLibsASMAnalysis, teavmRelocatedLibsASMCommons, teavmRelocatedLibsASMTree, teavmRelocatedLibsASMUtil, teavmRelocatedLibsHPPC, teavmRelocatedLibsRhino, teavmMetaprogrammingAPI, - teavmMetaprogrammingImpl, teavmJodaTime, teavmJZLIB }; + teavmMetaprogrammingImpl, teavmJodaTime, teavmJZLIB, depJOrbis, depLang3, depHPPC, depJSR305 }; public static File teavmBridge = null; @@ -201,10 +205,12 @@ public class TeaVMBinaries { public static String[] getTeaVMRuntimeClasspath() { return new String[] { teavmJodaTime.file.getAbsolutePath(), teavmJZLIB.file.getAbsolutePath(), - teavmClasslib.file.getAbsolutePath(), teavmInterop.file.getAbsolutePath(), teavmJSO.file.getAbsolutePath(), - teavmJSOApis.file.getAbsolutePath(), teavmJSOImpl.file.getAbsolutePath(), - teavmMetaprogrammingAPI.file.getAbsolutePath(), teavmMetaprogrammingImpl.file.getAbsolutePath(), - teavmPlatform.file.getAbsolutePath(), teavmCore.file.getAbsolutePath() }; + teavmClasslib.file.getAbsolutePath(), teavmInterop.file.getAbsolutePath(), + teavmJSO.file.getAbsolutePath(), teavmJSOApis.file.getAbsolutePath(), + teavmJSOImpl.file.getAbsolutePath(), teavmMetaprogrammingAPI.file.getAbsolutePath(), + teavmMetaprogrammingImpl.file.getAbsolutePath(), teavmPlatform.file.getAbsolutePath(), + teavmCore.file.getAbsolutePath(), depJOrbis.file.getAbsolutePath(), depLang3.file.getAbsolutePath(), + depHPPC.file.getAbsolutePath(), depJSR305.file.getAbsolutePath() }; } } diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/headless/CompileLatestClientHeadless.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/headless/CompileLatestClientHeadless.java index fe1b5a1c..bfb23933 100644 --- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/headless/CompileLatestClientHeadless.java +++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/headless/CompileLatestClientHeadless.java @@ -62,7 +62,7 @@ public class CompileLatestClientHeadless { System.out.println(); System.out.println("Launching client compiler..."); - System.out.println("Copyright (c) 2022-2024 lax1dude"); + System.out.println("Copyright (c) 2022-2025 lax1dude"); System.out.println(); boolean yes = false; @@ -327,6 +327,7 @@ public class CompileLatestClientHeadless { new File(repositoryFolder, "sources/protocol-game/java"), new File(repositoryFolder, "sources/protocol-relay/java"), new File(repositoryFolder, "sources/teavm/java"), + new File(repositoryFolder, "sources/teavm/resources"), new File(repositoryFolder, "sources/teavm-boot-menu/java")); }catch(IOException ex) { throw new CompileFailureException("failed to run javac compiler! " + ex.toString(), ex); @@ -404,11 +405,11 @@ public class CompileLatestClientHeadless { File classesJS = new File(outputDirectory, "classes.js"); - if(!ES6Compat.patchClassesJS(classesJS, new File(repositoryFolder, "sources/setup/workspace_template/javascript/ES6ShimScript.txt"))) { + if(!ES6Compat.patchClassesJS(classesJS, new File(repositoryFolder, "sources/setup/workspace_template/target_teavm_javascript/javascript/ES6ShimScript.txt"))) { System.err.println("Error: could not inject shim, continuing anyway because it is not required"); } - File epkCompiler = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/CompileEPK.jar"); + File epkCompiler = new File(repositoryFolder, "sources/setup/workspace_template/target_teavm_javascript/buildtools/CompileEPK.jar"); if(!epkCompiler.exists()) { throw new CompileFailureException("EPKCompiler JAR file is missing: " + epkCompiler.getAbsolutePath()); @@ -586,7 +587,7 @@ public class CompileLatestClientHeadless { } } } - File offlineDownloadGenerator = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/MakeOfflineDownload.jar"); + File offlineDownloadGenerator = new File(repositoryFolder, "sources/setup/workspace_template/target_teavm_javascript/buildtools/MakeOfflineDownload.jar"); MakeOfflineDownload.compilerMain(offlineDownloadGenerator, new String[] { offlineTemplateArg.getAbsolutePath(), classesJS.getAbsolutePath(), (new File(outputDirectory, "assets.epk")).getAbsolutePath(), diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/diff/PullRequestTask.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/diff/PullRequestTask.java index 85f2f950..089c61ab 100644 --- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/diff/PullRequestTask.java +++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/diff/PullRequestTask.java @@ -68,7 +68,9 @@ public class PullRequestTask { File originalSourceMain = new File(EaglerBuildTools.repositoryRoot, "sources/main/java"); File originalSourceProtoGame = new File(EaglerBuildTools.repositoryRoot, "sources/protocol-game/java"); File originalSourceProtoRelay = new File(EaglerBuildTools.repositoryRoot, "sources/protocol-relay/java"); + File originalSourcePlatformAPI = new File(EaglerBuildTools.repositoryRoot, "sources/platform-api/java"); File originalSourceTeaVM = new File(EaglerBuildTools.repositoryRoot, "sources/teavm/java"); + File originalSourceTeaVMRes = new File(EaglerBuildTools.repositoryRoot, "sources/teavm/resources"); File originalSourceTeaVMC = new File(EaglerBuildTools.repositoryRoot, "sources/teavmc-classpath/resources"); File originalSourceBootMenu = new File(EaglerBuildTools.repositoryRoot, "sources/teavm-boot-menu/java"); File originalSourceLWJGL = new File(EaglerBuildTools.repositoryRoot, "sources/lwjgl/java"); @@ -84,7 +86,9 @@ public class PullRequestTask { File diffFromGame = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/game/java"); File diffFromProtoGame = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/protocol-game/java"); File diffFromProtoRelay = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/protocol-relay/java"); + File diffFromPlatformAPI = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/platform-api/java"); File diffFromTeaVM = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/teavm/java"); + File diffFromTeaVMRes = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/teavm/resources"); File diffFromBootMenu = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/teavm-boot-menu/java"); File diffFromTeaVMC = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/teavmc-classpath/resources"); File diffFromLWJGL = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/lwjgl/java"); @@ -149,12 +153,24 @@ public class PullRequestTask { } System.out.println("Found " + i + " changed files in /src/protocol-relay/java/"); + i = copyAllModified(diffFromPlatformAPI, originalSourcePlatformAPI); + if(i > 0) { + flag = true; + } + System.out.println("Found " + i + " changed files in /src/platform-api/java/"); + i = copyAllModified(diffFromTeaVM, originalSourceTeaVM); if(i > 0) { flag = true; } System.out.println("Found " + i + " changed files in /src/teavm/java/"); + i = copyAllModified(diffFromTeaVMRes, originalSourceTeaVMRes); + if(i > 0) { + flag = true; + } + System.out.println("Found " + i + " changed files in /src/teavm/resources/"); + i = copyAllModified(diffFromBootMenu, originalSourceBootMenu); if(i > 0) { flag = true; diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/init/SetupWorkspace.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/init/SetupWorkspace.java index 4f1378f6..67b84c45 100644 --- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/init/SetupWorkspace.java +++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/init/SetupWorkspace.java @@ -124,9 +124,11 @@ public class SetupWorkspace { File repoSourcesSetup = new File(repoSources, "setup/workspace_template"); File repoSourcesMain = new File(repoSources, "main/java"); File repoSourcesTeaVM = new File(repoSources, "teavm/java"); + File repoSourcesTeaVMRes = new File(repoSources, "teavm/resources"); File repoSourcesLWJGL = new File(repoSources, "lwjgl/java"); File repoSourcesProtoGame = new File(repoSources, "protocol-game/java"); File repoSourcesProtoRelay = new File(repoSources, "protocol-relay/java"); + File repoSourcesPlatformAPI = new File(repoSources, "platform-api/java"); File repoSourcesBootMenu = new File(repoSources, "teavm-boot-menu/java"); File repoSourcesTeavmCRes = new File(repoSources, "teavmc-classpath/resources"); File repoSourcesWASMGCTeaVMJava = new File(repoSources, "wasm-gc-teavm/java"); @@ -139,8 +141,10 @@ public class SetupWorkspace { File srcGameJava = new File(workspaceDirectory, "src/game/java"); File srcLWJGLJava = new File(workspaceDirectory, "src/lwjgl/java"); File srcTeaVMJava = new File(workspaceDirectory, "src/teavm/java"); + File srcTeaVMRes = new File(workspaceDirectory, "src/teavm/resources"); File srcProtoGame = new File(workspaceDirectory, "src/protocol-game/java"); File srcProtoRelay = new File(workspaceDirectory, "src/protocol-relay/java"); + File srcPlatformAPI = new File(workspaceDirectory, "src/platform-api/java"); File srcBootMenu = new File(workspaceDirectory, "src/teavm-boot-menu/java"); File srcTeavmCRes = new File(workspaceDirectory, "src/teavmc-classpath/resources"); File srcWASMGCTeaVMJava = new File(workspaceDirectory, "src/wasm-gc-teavm/java"); @@ -150,7 +154,9 @@ public class SetupWorkspace { File srcWASMGCTeaVMLoaderJS = new File(workspaceDirectory, "src/wasm-gc-teavm-loader/js"); File resourcesExtractTo = new File(workspaceDirectory, "desktopRuntime/resources"); File mcLanguagesZip = new File(mcTmpDirectory, "minecraft_languages.zip"); - File mcLanguagesExtractTo = new File(workspaceDirectory, "javascript/lang"); + File localLibsZip = new File(repoSources, "setup/local-libs.zip"); + File mcLanguagesExtractTo = new File(workspaceDirectory, "target_teavm_javascript/javascript/lang"); + File localLibsExtractTo = new File(workspaceDirectory, "gradle/local-libs"); System.out.println("Copying files from \"/setup/workspace_template/\" to \"" + workspaceDirectory.getName() + "\"..."); @@ -161,23 +167,19 @@ public class SetupWorkspace { throw ex; } - String os = System.getProperty("os.name").toLowerCase(); - if(os.contains("linux") || os.contains("macos") || os.contains("osx")) { - File gradleW = new File(workspaceDirectory, "gradlew"); - if(!gradleW.setExecutable(true)) { - System.err.println("ERROR: could not set executable bit on 'gradlew'!"); - System.err.println("Enter the root directory of the repository and run 'chmod +x gradlew' if you need access to the gradlew command"); - } - } - File existingGi = new File(workspaceDirectory, ".gitignore"); if((existingGi.exists() && !existingGi.delete()) || !(new File(workspaceDirectory, ".gitignore.default").renameTo(existingGi))) { System.err.println("ERROR: Could not rename \".gitignore.default\" to \".gitignore\" in the workspace directory!"); } - existingGi = new File(workspaceDirectory, "wasm_gc_teavm/.gitignore"); - if((existingGi.exists() && !existingGi.delete()) || !(new File(workspaceDirectory, "wasm_gc_teavm/.gitignore.default").renameTo(existingGi))) { - System.err.println("ERROR: Could not rename \"wasm_gc_teavm/.gitignore.default\" to \"wasm_gc_teavm/.gitignore\" in the workspace directory!"); + existingGi = new File(workspaceDirectory, "target_teavm_javascript/.gitignore"); + if((existingGi.exists() && !existingGi.delete()) || !(new File(workspaceDirectory, "target_teavm_javascript/.gitignore.default").renameTo(existingGi))) { + System.err.println("ERROR: Could not rename \"target_teavm_javascript/.gitignore.default\" to \"target_teavm_javascript/.gitignore\" in the workspace directory!"); + } + + existingGi = new File(workspaceDirectory, "target_teavm_wasm_gc/.gitignore"); + if((existingGi.exists() && !existingGi.delete()) || !(new File(workspaceDirectory, "target_teavm_wasm_gc/.gitignore.default").renameTo(existingGi))) { + System.err.println("ERROR: Could not rename \"target_teavm_wasm_gc/.gitignore.default\" to \"target_teavm_wasm_gc/.gitignore\" in the workspace directory!"); } if(repoSourcesTeaVM.isDirectory()) { @@ -195,6 +197,21 @@ public class SetupWorkspace { } } + if(repoSourcesTeaVMRes.isDirectory()) { + System.out.println("Copying files from \"/sources/teavm/resources/\" to workspace..."); + + try { + if(!srcTeaVMRes.isDirectory() && !srcTeaVMRes.mkdirs()) { + System.err.println("ERROR: Could not create destination directory!"); + return false; + } + FileUtils.copyDirectory(repoSourcesTeaVMRes, srcTeaVMRes); + }catch(IOException ex) { + System.err.println("ERROR: could not copy \"/sources/teavm/resources/\" to \"" + srcTeaVMRes.getAbsolutePath() + "\"!"); + throw ex; + } + } + System.out.println("Copying files from \"/sources/main/java/\" to workspace..."); try { @@ -238,6 +255,21 @@ public class SetupWorkspace { } } + if(repoSourcesPlatformAPI.isDirectory()) { + System.out.println("Copying files from \"/sources/platform-api/java/\" to workspace..."); + + try { + if(!srcPlatformAPI.isDirectory() && !srcPlatformAPI.mkdirs()) { + System.err.println("ERROR: Could not create destination directory!"); + return false; + } + FileUtils.copyDirectory(repoSourcesPlatformAPI, srcPlatformAPI); + }catch(IOException ex) { + System.err.println("ERROR: could not copy \"/sources/platform-api/java/\" to \"" + srcPlatformAPI.getAbsolutePath() + "\"!"); + throw ex; + } + } + if(repoSourcesTeavmCRes.isDirectory()) { System.out.println("Copying files from \"/sources/teavmc-classpath/resources/\" to workspace..."); @@ -448,7 +480,7 @@ public class SetupWorkspace { minecraftResJar.delete(); } - System.out.println("Extracting files from \"minecraft_languages.zip\" to \"/javascript/lang/\"..."); + System.out.println("Extracting files from \"minecraft_languages.zip\" to \"/target_teavm_javascript/javascript/lang/\"..."); try { extractJarTo(mcLanguagesZip, mcLanguagesExtractTo); @@ -458,12 +490,22 @@ public class SetupWorkspace { throw ex; } - System.out.println("Creating eclipse project for desktop runtime..."); - if(!createDesktopRuntimeProject(new File(repoSources, "setup/eclipseProjectFiles"), workspaceDirectory)) { - System.err.println("ERROR: could not create eclipse project for desktop runtime!"); - return false; + System.out.println("Extracting files from \"local-libs.zip\" to \"/gradle/local-libs/\"..."); + + try { + extractJarTo(localLibsZip, localLibsExtractTo); + }catch(IOException ex) { + System.err.println("ERROR: could not extract \"" + localLibsZip.getName() + "\" to \"" + + localLibsExtractTo.getAbsolutePath() + "\"!"); + throw ex; } +// System.out.println("Creating eclipse project for desktop runtime..."); +// if(!createDesktopRuntimeProject(new File(repoSources, "setup/eclipseProjectFiles"), workspaceDirectory)) { +// System.err.println("ERROR: could not create eclipse project for desktop runtime!"); +// return false; +// } + return true; } @@ -497,6 +539,7 @@ public class SetupWorkspace { return cnt; } + @Deprecated private static boolean createDesktopRuntimeProject(File templateFolderIn, File workspaceDirectory) throws Throwable { File desktopRuntimeDirectory = new File(workspaceDirectory, "desktopRuntime"); File desktopRuntimeProjectDir = new File(desktopRuntimeDirectory, "eclipseProject"); diff --git a/client_version b/client_version index 6a4763ae..7d42c77c 100644 --- a/client_version +++ b/client_version @@ -1 +1 @@ -u50 \ No newline at end of file +u51 \ No newline at end of file diff --git a/patches/minecraft/delete.txt b/patches/minecraft/delete.txt index 2f01ea72..527d48db 100644 --- a/patches/minecraft/delete.txt +++ b/patches/minecraft/delete.txt @@ -1,4 +1,4 @@ -# 148 files to delete: +# 149 files to delete: net/minecraft/client/renderer/VertexBufferUploader.java net/minecraft/realms/DisconnectedRealmsScreen.java net/minecraft/client/stream/Metadata.java @@ -14,6 +14,7 @@ net/minecraft/command/server/CommandSaveAll.java net/minecraft/realms/RealmsVertexFormat.java net/minecraft/network/NettyCompressionDecoder.java net/minecraft/profiler/PlayerUsageSnooper.java +net/minecraft/util/MinecraftError.java net/minecraft/command/server/CommandPublishLocalServer.java net/minecraft/command/CommandDebug.java net/minecraft/client/renderer/chunk/VboChunkFactory.java diff --git a/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.edit.java b/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.edit.java index fd2411cf..b32a4f27 100644 --- a/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.edit.java +++ b/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.edit.java @@ -18,23 +18,29 @@ ~ import net.minecraft.client.resources.I18n; -> DELETE 9 @ 9 : 11 +> DELETE 1 @ 1 : 2 + +> DELETE 7 @ 7 : 9 > DELETE 3 @ 3 : 6 -> CHANGE 22 : 24 @ 22 : 32 +> CHANGE 14 : 15 @ 14 : 19 + +~ if (this.mc.running) { + +> CHANGE 3 : 5 @ 3 : 13 ~ GlStateManager.ortho(0.0D, mc.scaledResolution.getScaledWidth_double(), ~ mc.scaledResolution.getScaledHeight_double(), 0.0D, 100.0D, 300.0D); -> INSERT 19 : 37 @ 19 +> CHANGE 7 : 8 @ 7 : 12 + +~ if (this.mc.running) { + +> INSERT 7 : 21 @ 7 + public void eaglerShow(String line1, String line2) { -+ if (!this.mc.running) { -+ if (!this.field_73724_e) { -+ throw new MinecraftError(); -+ } -+ } else { ++ if (this.mc.running) { + this.systemTime = 0L; + this.currentlyDisplayedText = line1; + this.message = line2; @@ -48,7 +54,11 @@ + } + -> CHANGE 9 : 10 @ 9 : 10 +> CHANGE 1 : 2 @ 1 : 6 + +~ if (this.mc.running) { + +> CHANGE 3 : 4 @ 3 : 4 ~ ScaledResolution scaledresolution = mc.scaledResolution; diff --git a/patches/minecraft/net/minecraft/client/Minecraft.edit.java b/patches/minecraft/net/minecraft/client/Minecraft.edit.java index b1001f50..a85fdf85 100644 --- a/patches/minecraft/net/minecraft/client/Minecraft.edit.java +++ b/patches/minecraft/net/minecraft/client/Minecraft.edit.java @@ -18,14 +18,13 @@ > DELETE 1 @ 1 : 4 -> CHANGE 1 : 75 @ 1 : 4 +> CHANGE 1 : 76 @ 1 : 4 ~ ~ import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache; ~ import net.lax1dude.eaglercraft.v1_8.Display; ~ import net.lax1dude.eaglercraft.v1_8.EagRuntime; ~ import net.lax1dude.eaglercraft.v1_8.EagUtils; -~ import net.lax1dude.eaglercraft.v1_8.EaglerXBungeeVersion; ~ import net.lax1dude.eaglercraft.v1_8.HString; ~ import net.lax1dude.eaglercraft.v1_8.IOUtils; ~ import net.lax1dude.eaglercraft.v1_8.Keyboard; @@ -43,6 +42,7 @@ ~ import net.lax1dude.eaglercraft.v1_8.futures.FutureTask; ~ import net.lax1dude.eaglercraft.v1_8.futures.ListenableFuture; ~ import net.lax1dude.eaglercraft.v1_8.futures.ListenableFutureTask; +~ import net.lax1dude.eaglercraft.v1_8.internal.ContextLostError; ~ import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformType; ~ import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime; ~ import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC; @@ -76,6 +76,7 @@ ~ import net.lax1dude.eaglercraft.v1_8.socket.AddressResolver; ~ import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager; ~ import net.lax1dude.eaglercraft.v1_8.socket.RateLimitTracker; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.StateFlags; ~ import net.lax1dude.eaglercraft.v1_8.sp.IntegratedServerState; ~ import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController; ~ import net.lax1dude.eaglercraft.v1_8.sp.SkullCommand; @@ -139,7 +140,9 @@ + import net.minecraft.util.ChatStyle; + import net.minecraft.util.EnumChatFormatting; -> INSERT 7 : 8 @ 7 +> DELETE 3 @ 3 : 4 + +> INSERT 3 : 4 @ 3 + import net.minecraft.util.MovingObjectPosition.MovingObjectType; @@ -256,12 +259,14 @@ ~ this.runGameLoop(); -> DELETE 4 @ 4 : 21 +> CHANGE 4 : 5 @ 4 : 21 + +~ return; > CHANGE 1 : 14 @ 1 : 3 -~ } catch (MinecraftError var12) { -~ // ?? +~ } catch (ContextLostError err) { +~ throw err; ~ } catch (ReportedException reportedexception) { ~ this.addGraphicsAndWorldToCrashReport(reportedexception.getCrashReport()); ~ logger.fatal("Reported exception thrown!", reportedexception); @@ -555,8 +560,10 @@ ~ long i = EagRuntime.nanoTime(); ~ if (Display.isCloseRequested()) { -> INSERT 3 : 6 @ 3 +> INSERT 3 : 8 @ 3 ++ Display.checkContextLost(); ++ + PointerInputAbstraction.runGameLoop(); + this.gameSettings.touchscreen = PointerInputAbstraction.isTouchMode(); + @@ -583,34 +590,31 @@ > DELETE 1 @ 1 : 2 -> DELETE 1 @ 1 : 11 +> CHANGE 1 : 6 @ 1 : 3 -> CHANGE 1 : 12 @ 1 : 7 +~ +~ EaglercraftGPU.optimize(); +~ _wglBindFramebuffer(0x8D40, null); +~ GlStateManager.viewport(0, 0, this.displayWidth, this.displayHeight); +~ GlStateManager.clearColor(0.0f, 0.0f, 0.0f, 1.0f); -~ if (!Display.contextLost()) { -~ EaglercraftGPU.optimize(); -~ _wglBindFramebuffer(0x8D40, null); -~ GlStateManager.viewport(0, 0, this.displayWidth, this.displayHeight); -~ GlStateManager.clearColor(0.0f, 0.0f, 0.0f, 1.0f); -~ GlStateManager.pushMatrix(); -~ GlStateManager.clear(16640); -~ GlStateManager.enableTexture2D(); -~ if (this.thePlayer != null && this.thePlayer.isEntityInsideOpaqueBlock()) { -~ this.gameSettings.thirdPersonView = 0; -~ } +> DELETE 2 @ 2 : 4 -> CHANGE 1 : 3 @ 1 : 5 +> DELETE 5 @ 5 : 6 -~ if (!this.skipRenderWorld) { -~ this.entityRenderer.func_181560_a(this.timer.renderPartialTicks, i); +> DELETE 1 @ 1 : 2 -> CHANGE 2 : 5 @ 2 : 7 +> DELETE 1 @ 1 : 2 -~ this.guiAchievement.updateAchievementWindow(); -~ this.touchOverlayRenderer.render(displayWidth, displayHeight, scaledResolution); -~ GlStateManager.popMatrix(); +> DELETE 2 @ 2 : 15 -> DELETE 2 @ 2 : 12 +> CHANGE 1 : 2 @ 1 : 2 + +~ this.touchOverlayRenderer.render(displayWidth, displayHeight, scaledResolution); + +> CHANGE 1 : 2 @ 1 : 8 + +~ > DELETE 1 @ 1 : 9 @@ -777,7 +781,7 @@ > CHANGE 4 : 6 @ 4 : 5 -~ VoiceClientController.tickVoiceClient(this); +~ VoiceClientController.tickVoiceClient(); ~ > DELETE 1 @ 1 : 2 @@ -1047,29 +1051,29 @@ ~ if (bungeeOutdatedMsgTimer > 0) { ~ if (--bungeeOutdatedMsgTimer == 0 && this.thePlayer.sendQueue != null) { ~ String pluginBrand = this.thePlayer.sendQueue.getNetworkManager().getPluginBrand(); -~ String pluginVersion = this.thePlayer.sendQueue.getNetworkManager().getPluginVersion(); -~ if (pluginBrand != null && pluginVersion != null -~ && EaglerXBungeeVersion.isUpdateToPluginAvailable(pluginBrand, pluginVersion)) { +~ if (pluginBrand != null && ("EaglercraftXBungee".equals(pluginBrand) +~ || "EaglercraftXVelocity".equals(pluginBrand))) { ~ String pfx = EnumChatFormatting.GOLD + "[EagX]" + EnumChatFormatting.AQUA; ~ ingameGUI.getChatGUI().printChatMessage( ~ new ChatComponentText(pfx + " ---------------------------------------")); +~ ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(pfx + " This server is running " +~ + EnumChatFormatting.YELLOW + pluginBrand + EnumChatFormatting.AQUA + ",")); ~ ingameGUI.getChatGUI().printChatMessage( -~ new ChatComponentText(pfx + " This server appears to be using version " -~ + EnumChatFormatting.YELLOW + pluginVersion)); +~ new ChatComponentText(pfx + " which has been discontinued by lax1dude.")); +~ ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(pfx)); ~ ingameGUI.getChatGUI().printChatMessage( -~ new ChatComponentText(pfx + " of the EaglerXBungee plugin which is outdated")); +~ new ChatComponentText(pfx + " If you are the admin of this server, please")); +~ ingameGUI.getChatGUI().printChatMessage( +~ new ChatComponentText(pfx + " upgrade to EaglercraftXServer if you want to")); +~ ingameGUI.getChatGUI().printChatMessage( +~ new ChatComponentText(pfx + " to continue to receive support and bugfixes.")); ~ ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(pfx)); ~ ingameGUI.getChatGUI() -~ .printChatMessage(new ChatComponentText(pfx + " If you are the admin update to " -~ + EnumChatFormatting.YELLOW + EaglerXBungeeVersion.getPluginVersion() -~ + EnumChatFormatting.AQUA + " or newer")); -~ ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(pfx)); -~ ingameGUI.getChatGUI().printChatMessage((new ChatComponentText(pfx + " Click: ")) -~ .appendSibling((new ChatComponentText("" + EnumChatFormatting.GREEN -~ + EnumChatFormatting.UNDERLINE + EaglerXBungeeVersion.getPluginButton())) -~ .setChatStyle((new ChatStyle()).setChatClickEvent( -~ new ClickEvent(ClickEvent.Action.EAGLER_PLUGIN_DOWNLOAD, -~ "plugin_download.zip"))))); +~ .printChatMessage((new ChatComponentText(pfx + " " + EnumChatFormatting.GREEN +~ + EnumChatFormatting.UNDERLINE + "https://lax1dude.net/eaglerxserver")) +~ .setChatStyle((new ChatStyle()) +~ .setChatClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, +~ "https://lax1dude.net/eaglerxserver")))); ~ ingameGUI.getChatGUI().printChatMessage( ~ new ChatComponentText(pfx + " ---------------------------------------")); ~ } @@ -1228,7 +1232,7 @@ + EaglerProfile.clearServerSkinOverride(); + PauseMenuCustomizeState.reset(); + ClientUUIDLoadingCache.flushRequestCache(); -+ ClientUUIDLoadingCache.resetFlags(); ++ StateFlags.reset(); + WebViewOverlayController.setPacketSendCallback(null); > DELETE 1 @ 1 : 7 @@ -1254,7 +1258,11 @@ ~ public void middleClickMouse() { -> CHANGE 127 : 128 @ 127 : 128 +> CHANGE 76 : 77 @ 76 : 77 + +~ if (!EntityList.entityEggs.containsKey(i)) { + +> CHANGE 50 : 51 @ 50 : 51 ~ return EagRuntime.getVersion(); diff --git a/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.edit.java index d051b587..377f5699 100644 --- a/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.edit.java +++ b/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.edit.java @@ -10,11 +10,10 @@ + import java.io.IOException; + -> CHANGE 2 : 18 @ 2 : 15 +> CHANGE 2 : 17 @ 2 : 15 ~ ~ import net.lax1dude.eaglercraft.v1_8.EagRuntime; -~ import net.lax1dude.eaglercraft.v1_8.EaglerXBungeeVersion; ~ import net.lax1dude.eaglercraft.v1_8.Keyboard; ~ import net.lax1dude.eaglercraft.v1_8.Mouse; ~ import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore; @@ -207,7 +206,7 @@ + GlStateManager.scale(0.75f, 0.75f, 0.75f); + GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); + -+ String text = EaglerXBungeeVersion.getPluginButton(); ++ String text = "Download EaglerXServer"; + int w = mc.fontRendererObj.getStringWidth(text); + boolean hover = xx > width - 5 - (w + 5) * 3 / 4 && yy > 1 && xx < width - 2 && yy < 12; + if (hover) { @@ -268,12 +267,12 @@ > INSERT 2 : 9 @ 2 -+ String text = EaglerXBungeeVersion.getPluginButton(); ++ String text = "Download EaglerXServer"; + int w = mc.fontRendererObj.getStringWidth(text); + if (parInt1 > width - 5 - (w + 5) * 3 / 4 && parInt2 > 1 && parInt1 < width - 2 && parInt2 < 12) { + this.mc.getSoundHandler() + .playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F)); -+ EaglerXBungeeVersion.startPluginDownload(); ++ EagRuntime.openLink("https://lax1dude.net/eaglerxserver"); + } > INSERT 11 : 15 @ 11 diff --git a/patches/minecraft/net/minecraft/client/gui/GuiScreen.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiScreen.edit.java index 969fead5..71b96585 100644 --- a/patches/minecraft/net/minecraft/client/gui/GuiScreen.edit.java +++ b/patches/minecraft/net/minecraft/client/gui/GuiScreen.edit.java @@ -9,7 +9,7 @@ > DELETE 1 @ 1 : 3 -> INSERT 4 : 29 @ 4 +> INSERT 4 : 28 @ 4 + + import net.lax1dude.eaglercraft.v1_8.internal.EnumTouchEvent; @@ -22,7 +22,6 @@ + import com.google.common.collect.Sets; + + import net.lax1dude.eaglercraft.v1_8.EagRuntime; -+ import net.lax1dude.eaglercraft.v1_8.EaglerXBungeeVersion; + import net.lax1dude.eaglercraft.v1_8.Keyboard; + import net.lax1dude.eaglercraft.v1_8.Mouse; + import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState; @@ -221,7 +220,7 @@ ~ // rip -> CHANGE 5 : 15 @ 5 : 8 +> CHANGE 5 : 12 @ 5 : 11 ~ /* ~ * ChatUserInfo chatuserinfo = @@ -230,16 +229,8 @@ ~ * GuiTwitchUserMode(this.mc.getTwitchStream(), chatuserinfo)); } else { } ~ */ ~ LOGGER.error("Tried to handle twitch user but couldn\'t find them!"); -~ } else if (clickevent.getAction() == ClickEvent.Action.EAGLER_PLUGIN_DOWNLOAD) { -~ if (EaglerXBungeeVersion.pluginFileEPK.equals(clickevent.getValue())) { -~ EaglerXBungeeVersion.startPluginDownload(); -> CHANGE 1 : 3 @ 1 : 2 - -~ LOGGER.error("Invalid plugin download from EPK was blocked: {}", -~ EaglerXBungeeVersion.pluginFileEPK); - -> CHANGE 24 : 49 @ 24 : 26 +> CHANGE 23 : 48 @ 23 : 25 ~ protected void touchStarted(int parInt1, int parInt2, int parInt3) { ~ if (shouldTouchGenerateMouseEvents()) { diff --git a/patches/minecraft/net/minecraft/client/gui/spectator/PlayerMenuObject.edit.java b/patches/minecraft/net/minecraft/client/gui/spectator/PlayerMenuObject.edit.java index 2ec2c230..3346c455 100644 --- a/patches/minecraft/net/minecraft/client/gui/spectator/PlayerMenuObject.edit.java +++ b/patches/minecraft/net/minecraft/client/gui/spectator/PlayerMenuObject.edit.java @@ -23,6 +23,6 @@ > CHANGE 11 : 13 @ 11 : 12 ~ Minecraft.getMinecraft().getTextureManager().bindTexture( -~ Minecraft.getMinecraft().getNetHandler().getSkinCache().getSkin(profile).getResourceLocation()); +~ Minecraft.getMinecraft().getNetHandler().getTextureCache().getPlayerSkin(profile).getLocation()); > EOF diff --git a/patches/minecraft/net/minecraft/client/multiplayer/GuiConnecting.edit.java b/patches/minecraft/net/minecraft/client/multiplayer/GuiConnecting.edit.java index d4d97c46..ed910aef 100644 --- a/patches/minecraft/net/minecraft/client/multiplayer/GuiConnecting.edit.java +++ b/patches/minecraft/net/minecraft/client/multiplayer/GuiConnecting.edit.java @@ -5,7 +5,7 @@ # Version: 1.0 # Author: lax1dude -> CHANGE 3 : 21 @ 3 : 6 +> CHANGE 2 : 16 @ 2 : 6 ~ import java.util.List; ~ @@ -17,22 +17,14 @@ ~ import net.lax1dude.eaglercraft.v1_8.internal.PlatformNetworking; ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; ~ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; +~ import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile; ~ import net.lax1dude.eaglercraft.v1_8.socket.AddressResolver; -~ import net.lax1dude.eaglercraft.v1_8.socket.ConnectionHandshake; -~ import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager; ~ import net.lax1dude.eaglercraft.v1_8.socket.RateLimitTracker; -~ import net.lax1dude.eaglercraft.v1_8.socket.WebSocketNetworkManager; -~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants; -~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; -~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake.HandshakerHandler; -> CHANGE 4 : 5 @ 4 : 8 +> DELETE 4 @ 4 : 8 -~ import net.minecraft.client.network.NetHandlerPlayClient; - -> CHANGE 2 : 3 @ 2 : 5 - -~ import net.minecraft.network.play.client.C17PacketCustomPayload; +> DELETE 1 @ 1 : 5 > DELETE 1 @ 1 : 4 @@ -41,17 +33,13 @@ > CHANGE 1 : 7 @ 1 : 2 ~ private IWebSocketClient webSocket; -~ private EaglercraftNetworkManager networkManager; +~ private HandshakerHandler handshaker; ~ private String currentAddress; ~ private String currentPassword; ~ private boolean allowPlaintext; ~ private boolean allowCookies; -> INSERT 1 : 2 @ 1 - -+ private boolean hasOpened; - -> INSERT 1 : 2 @ 1 +> INSERT 2 : 3 @ 2 + private int timer = 0; @@ -155,12 +143,15 @@ ~ new ChatComponentText("Could not open WebSocket to \"" + currentAddress + "\"!"))); ~ } -> CHANGE 1 : 81 @ 1 : 2 +> CHANGE 1 : 38 @ 1 : 2 -~ if (webSocket.getState() == EnumEaglerConnectionState.CONNECTED) { -~ if (!hasOpened) { -~ hasOpened = true; +~ EnumEaglerConnectionState connState = webSocket.getState(); +~ if (connState == EnumEaglerConnectionState.CONNECTED) { +~ if (handshaker == null) { +~ this.mc.getSession().reset(); +~ ~ logger.info("Logging in: {}", currentAddress); +~ ~ byte[] cookieData = null; ~ if (allowCookies) { ~ ServerCookieDataStore.ServerCookie cookie = ServerCookieDataStore @@ -169,61 +160,15 @@ ~ cookieData = cookie.cookie; ~ } ~ } -~ if (ConnectionHandshake.attemptHandshake(this.mc, webSocket, this, previousGuiScreen, -~ currentPassword, allowPlaintext, allowCookies, cookieData)) { -~ logger.info("Handshake Success"); -~ webSocket.setEnableStringFrames(false); -~ webSocket.clearStringFrames(); -~ this.networkManager = new WebSocketNetworkManager(webSocket); -~ this.networkManager.setPluginInfo(ConnectionHandshake.pluginBrand, -~ ConnectionHandshake.pluginVersion); -~ mc.bungeeOutdatedMsgTimer = 80; -~ mc.clearTitles(); -~ this.networkManager.setConnectionState(EnumConnectionState.PLAY); -~ NetHandlerPlayClient netHandler = new NetHandlerPlayClient(this.mc, previousGuiScreen, -~ this.networkManager, this.mc.getSession().getProfile()); -~ this.networkManager.setNetHandler(netHandler); -~ netHandler.setEaglerMessageController(new GameProtocolMessageController( -~ GamePluginMessageProtocol.getByVersion(ConnectionHandshake.protocolVersion), -~ GamePluginMessageConstants.CLIENT_TO_SERVER, -~ GameProtocolMessageController -~ .createClientHandler(ConnectionHandshake.protocolVersion, netHandler), -~ (ch, msg) -> netHandler.addToSendQueue(new C17PacketCustomPayload(ch, msg)))); -~ } else { -~ if (mc.currentScreen == this) { -~ checkRatelimit(); -~ logger.info("Handshake Failure"); -~ mc.getSession().reset(); -~ mc.displayGuiScreen( -~ new GuiDisconnected(previousGuiScreen, "connect.failed", new ChatComponentText( -~ "Handshake Failure\n\nAre you sure this is an eagler 1.8 server?"))); -~ } -~ webSocket.close(); -~ return; -~ } -~ } -~ if (this.networkManager != null) { -~ try { -~ this.networkManager.processReceivedPackets(); -~ } catch (IOException ex) { -~ } +~ +~ handshaker = new HandshakerHandler(this, webSocket, EaglerProfile.getName(), currentPassword, +~ allowPlaintext, allowCookies, cookieData); ~ } +~ handshaker.tick(); ~ } else { -~ if (webSocket.getState() == EnumEaglerConnectionState.FAILED) { -~ if (!hasOpened) { -~ mc.getSession().reset(); -~ checkRatelimit(); -~ if (mc.currentScreen == this) { -~ if (RateLimitTracker.isProbablyLockedOut(currentAddress)) { -~ mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(previousGuiScreen)); -~ } else { -~ mc.displayGuiScreen(new GuiDisconnected(previousGuiScreen, "connect.failed", -~ new ChatComponentText("Connection Refused"))); -~ } -~ } -~ } -~ } else { -~ if (this.networkManager != null && this.networkManager.checkDisconnected()) { +~ if (handshaker != null) { +~ handshaker.tick(); +~ if (connState == EnumEaglerConnectionState.FAILED) { ~ this.mc.getSession().reset(); ~ checkRatelimit(); ~ if (mc.currentScreen == this) { @@ -263,16 +208,15 @@ ~ protected void actionPerformed(GuiButton parGuiButton) { -> INSERT 4 : 6 @ 4 +> CHANGE 2 : 3 @ 2 : 6 -+ } else if (this.webSocket != null) { -+ this.webSocket.close(); +~ this.webSocket.close(); -> CHANGE 9 : 10 @ 9 : 10 +> CHANGE 7 : 8 @ 7 : 8 -~ if (this.networkManager == null || !this.networkManager.isChannelOpen()) { +~ if (this.handshaker == null) { -> INSERT 9 : 34 @ 9 +> INSERT 9 : 43 @ 9 + + private void checkRatelimit() { @@ -299,5 +243,14 @@ + public boolean canCloseGui() { + return false; + } ++ ++ public static Minecraft getMC(GuiConnecting gui) { ++ return gui.mc; ++ } ++ ++ public static GuiScreen getPrevScreen(GuiConnecting gui) { ++ return gui.previousGuiScreen; ++ } ++ > EOF diff --git a/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.edit.java b/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.edit.java index aaf4c2d2..4b831b8f 100644 --- a/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.edit.java +++ b/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.edit.java @@ -18,7 +18,7 @@ + import net.minecraft.util.ChatComponentText; -> CHANGE 228 : 242 @ 228 : 229 +> CHANGE 228 : 241 @ 228 : 229 ~ try { ~ this.netClientHandler.getNetworkManager().processReceivedPackets(); @@ -30,8 +30,7 @@ ~ this.netClientHandler.getNetworkManager() ~ .closeChannel(new ChatComponentText("Exception thrown: " + ex.toString())); ~ } -~ this.netClientHandler.getSkinCache().flush(); -~ this.netClientHandler.getCapeCache().flush(); +~ this.netClientHandler.getTextureCache().runTick(); ~ this.netClientHandler.getNotifManager().runTick(); ~ ClientUUIDLoadingCache.update(); diff --git a/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.edit.java b/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.edit.java index 3ca29669..e6ca03f8 100644 --- a/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.edit.java +++ b/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.edit.java @@ -7,7 +7,7 @@ > DELETE 2 @ 2 : 8 -> CHANGE 4 : 28 @ 4 : 7 +> CHANGE 4 : 32 @ 4 : 7 ~ ~ import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache; @@ -19,11 +19,15 @@ ~ ~ import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; ~ import net.lax1dude.eaglercraft.v1_8.notifications.ServerNotificationManager; -~ import net.lax1dude.eaglercraft.v1_8.profile.ServerCapeCache; -~ import net.lax1dude.eaglercraft.v1_8.profile.ServerSkinCache; +~ import net.lax1dude.eaglercraft.v1_8.skin_cache.ServerTextureCache; ~ import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants; ~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; -~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.ClientMessageHandler; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake.StandardCaps; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.message.InjectedMessageController; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.message.LegacyMessageController; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.message.MessageController; ~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; ~ import net.lax1dude.eaglercraft.v1_8.sp.lan.LANClientNetworkManager; ~ import net.lax1dude.eaglercraft.v1_8.sp.socket.ClientIntegratedServerNetworkManager; @@ -68,70 +72,71 @@ ~ private final Map playerInfoMap = Maps.newHashMap(); -> CHANGE 2 : 12 @ 2 : 3 +> CHANGE 2 : 13 @ 2 : 3 ~ private boolean isIntegratedServer = false; ~ private final EaglercraftRandom avRandomizer = new EaglercraftRandom(); -~ private final ServerSkinCache skinCache; -~ private final ServerCapeCache capeCache; +~ private final ServerTextureCache textureCache; ~ private final ServerNotificationManager notifManager; ~ public boolean currentFNAWSkinAllowedState = true; ~ public boolean currentFNAWSkinForcedState = true; -~ private GameProtocolMessageController eaglerMessageController = null; -~ public boolean hasRequestedServerInfo = false; +~ private final MessageController eaglerMessageController; +~ public byte[] cachedServerInfoHash = null; ~ public byte[] cachedServerInfoData = null; +~ public boolean allowedDisplayWebview = false; +~ public boolean allowedDisplayWebviewYes = false; -> CHANGE 1 : 2 @ 1 : 2 +> CHANGE 1 : 3 @ 1 : 3 ~ public NetHandlerPlayClient(Minecraft mcIn, GuiScreen parGuiScreen, EaglercraftNetworkManager parNetworkManager, +~ GameProfile parGameProfile, GamePluginMessageProtocol eaglerProtocol) { -> INSERT 5 : 10 @ 5 +> INSERT 3 : 4 @ 3 + ++ this.netManager.setNetHandler(this); + +> INSERT 1 : 15 @ 1 -+ this.skinCache = new ServerSkinCache(this, mcIn.getTextureManager()); -+ this.capeCache = new ServerCapeCache(this, mcIn.getTextureManager()); -+ this.notifManager = new ServerNotificationManager(); + this.isIntegratedServer = (parNetworkManager instanceof ClientIntegratedServerNetworkManager) + || (parNetworkManager instanceof LANClientNetworkManager); ++ ClientMessageHandler handler = ClientMessageHandler.createClientHandler(eaglerProtocol.ver, this); ++ if (eaglerProtocol.ver >= 5) { ++ this.eaglerMessageController = new InjectedMessageController(eaglerProtocol, handler, ++ GamePluginMessageConstants.CLIENT_TO_SERVER, parNetworkManager::injectRawFrame); ++ parNetworkManager.setInjectedMessageController((InjectedMessageController) eaglerMessageController); ++ } else { ++ this.eaglerMessageController = new LegacyMessageController(eaglerProtocol, handler, ++ GamePluginMessageConstants.CLIENT_TO_SERVER, ++ (ch, msg) -> addToSendQueue(new C17PacketCustomPayload(ch, msg))); ++ } ++ this.textureCache = ServerTextureCache.create(this, mcIn.getTextureManager()); ++ this.notifManager = new ServerNotificationManager(mcIn.getTextureManager()); -> INSERT 4 : 7 @ 4 +> INSERT 4 : 6 @ 4 -+ this.skinCache.destroy(); -+ this.capeCache.destroy(); ++ this.textureCache.destroy(); + this.notifManager.destroy(); -> INSERT 2 : 51 @ 2 +> INSERT 2 : 38 @ 2 -+ public ServerSkinCache getSkinCache() { -+ return this.skinCache; -+ } -+ -+ public ServerCapeCache getCapeCache() { -+ return this.capeCache; ++ public ServerTextureCache getTextureCache() { ++ return this.textureCache; + } + + public ServerNotificationManager getNotifManager() { + return this.notifManager; + } + -+ public GameProtocolMessageController getEaglerMessageController() { ++ public MessageController getEaglerMessageController() { + return eaglerMessageController; + } + -+ public void setEaglerMessageController(GameProtocolMessageController eaglerMessageController) { -+ this.eaglerMessageController = eaglerMessageController; -+ } -+ + public GamePluginMessageProtocol getEaglerMessageProtocol() { -+ return eaglerMessageController != null ? eaglerMessageController.protocol : null; ++ return eaglerMessageController != null ? eaglerMessageController.getProtocol() : null; + } + + public void sendEaglerMessage(GameMessagePacket packet) { -+ try { -+ eaglerMessageController.sendPacket(packet); -+ } catch (IOException e) { -+ logger.error("Failed to send eaglercraft plugin message packet: " + packet); -+ logger.error(e); -+ } ++ eaglerMessageController.sendPacket(packet); + } + + public boolean webViewSendHandler(GameMessagePacket pkt) { @@ -142,7 +147,7 @@ + logger.error("WebView sent message on a dead handler!"); + return false; + } -+ if (eaglerMessageController.protocol.ver >= 4) { ++ if (eaglerMessageController.getProtocol().ver >= 4) { + sendEaglerMessage(pkt); + return true; + } else { @@ -158,12 +163,21 @@ ~ this.clientWorldController = new WorldClient(this, new WorldSettings(0L, packetIn.getGameType(), false, ~ packetIn.isHardcoreMode(), packetIn.getWorldType()), packetIn.getDimension(), packetIn.getDifficulty()); -> INSERT 11 : 15 @ 11 +> INSERT 11 : 24 @ 11 + if (VoiceClientController.isClientSupported()) { -+ VoiceClientController.initializeVoiceClient(this::sendEaglerMessage, eaglerMessageController.protocol.ver); ++ if (netManager.getServerCapabilities().hasCapability(StandardCaps.VOICE, 0)) { ++ VoiceClientController.initializeVoiceClient(this::sendEaglerMessage, ++ eaglerMessageController.getProtocol().ver); ++ } else { ++ VoiceClientController.initializeVoiceClient(null, -1); ++ } ++ } ++ if (netManager.getServerCapabilities().hasCapability(StandardCaps.WEBVIEW, 0)) { ++ WebViewOverlayController.setPacketSendCallback(this::webViewSendHandler); ++ } else { ++ WebViewOverlayController.setPacketSendCallback(null); + } -+ WebViewOverlayController.setPacketSendCallback(this::webViewSendHandler); > DELETE 3 @ 3 : 4 @@ -477,12 +491,11 @@ ~ for (int i = 0, l = lst.size(); i < l; ++i) { ~ S38PacketPlayerListItem.AddPlayerData s38packetplayerlistitem$addplayerdata = lst.get(i); -> CHANGE 1 : 6 @ 1 : 2 +> CHANGE 1 : 5 @ 1 : 2 ~ EaglercraftUUID uuid = s38packetplayerlistitem$addplayerdata.getProfile().getId(); ~ this.playerInfoMap.remove(uuid); -~ this.skinCache.evictSkin(uuid); -~ this.capeCache.evictCape(uuid); +~ this.textureCache.evictPlayer(uuid); ~ ClientUUIDLoadingCache.evict(uuid); > DELETE 34 @ 34 : 35 @@ -573,11 +586,12 @@ > DELETE 11 @ 11 : 13 -> INSERT 9 : 17 @ 9 +> INSERT 9 : 18 @ 9 -+ } else { ++ } else if (eaglerMessageController instanceof LegacyMessageController) { + try { -+ eaglerMessageController.handlePacket(packetIn.getChannelName(), packetIn.getBufferData()); ++ ((LegacyMessageController) eaglerMessageController).handlePacket(packetIn.getChannelName(), ++ packetIn.getBufferData()); + } catch (IOException e) { + logger.error("Couldn't read \"{}\" packet as an eaglercraft plugin message!", + packetIn.getChannelName()); diff --git a/patches/minecraft/net/minecraft/client/network/NetworkPlayerInfo.edit.java b/patches/minecraft/net/minecraft/client/network/NetworkPlayerInfo.edit.java index c78d1aa6..3f941b89 100644 --- a/patches/minecraft/net/minecraft/client/network/NetworkPlayerInfo.edit.java +++ b/patches/minecraft/net/minecraft/client/network/NetworkPlayerInfo.edit.java @@ -31,26 +31,24 @@ ~ return true; -> CHANGE 3 : 5 @ 3 : 4 +> CHANGE 3 : 4 @ 3 : 4 -~ return Minecraft.getMinecraft().getNetHandler().getSkinCache().getSkin(this.gameProfile) -~ .getSkinModel().profileSkinType; +~ return getEaglerSkinModel().profileSkinType; > CHANGE 2 : 5 @ 2 : 6 ~ public SkinModel getEaglerSkinModel() { -~ return Minecraft.getMinecraft().getNetHandler().getSkinCache().getSkin(this.gameProfile).getSkinModel(); +~ return Minecraft.getMinecraft().getNetHandler().getTextureCache().getPlayerSkin(this.gameProfile).getModel(); ~ } > CHANGE 1 : 3 @ 1 : 3 ~ public ResourceLocation getLocationSkin() { -~ return Minecraft.getMinecraft().getNetHandler().getSkinCache().getSkin(this.gameProfile).getResourceLocation(); +~ return Minecraft.getMinecraft().getNetHandler().getTextureCache().getPlayerSkin(this.gameProfile).getLocation(); -> CHANGE 3 : 5 @ 3 : 8 +> CHANGE 3 : 4 @ 3 : 8 -~ return Minecraft.getMinecraft().getNetHandler().getCapeCache().getCape(this.gameProfile.getId()) -~ .getResourceLocation(); +~ return Minecraft.getMinecraft().getNetHandler().getTextureCache().getPlayerCape(this.gameProfile); > DELETE 6 @ 6 : 33 diff --git a/patches/minecraft/net/minecraft/client/renderer/BlockFluidRenderer.edit.java b/patches/minecraft/net/minecraft/client/renderer/BlockFluidRenderer.edit.java index 13c8d476..c8253285 100644 --- a/patches/minecraft/net/minecraft/client/renderer/BlockFluidRenderer.edit.java +++ b/patches/minecraft/net/minecraft/client/renderer/BlockFluidRenderer.edit.java @@ -5,13 +5,12 @@ # Version: 1.0 # Author: lax1dude -> INSERT 2 : 8 @ 2 +> INSERT 2 : 7 @ 2 + import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerTextureAtlasSprite; + import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer; + import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.BlockVertexIDs; + import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DeferredStateManager; -+ import net.lax1dude.eaglercraft.v1_8.opengl.ext.dynamiclights.DynamicLightsStateManager; + import net.minecraft.block.Block; > DELETE 4 @ 4 : 6 @@ -25,7 +24,7 @@ + BlockPos tmp = new BlockPos(0, 0, 0); + boolean deferred = DeferredStateManager.isDeferredRenderer(); -+ boolean isDynamicLights = deferred || DynamicLightsStateManager.isDynamicLightsRender(); ++ boolean isDynamicLights = deferred;// || DynamicLightsStateManager.isDynamicLightsRender(); > INSERT 1 : 3 @ 1 diff --git a/patches/minecraft/net/minecraft/client/renderer/BlockModelRenderer.edit.java b/patches/minecraft/net/minecraft/client/renderer/BlockModelRenderer.edit.java index b229e828..303b4f20 100644 --- a/patches/minecraft/net/minecraft/client/renderer/BlockModelRenderer.edit.java +++ b/patches/minecraft/net/minecraft/client/renderer/BlockModelRenderer.edit.java @@ -5,14 +5,13 @@ # Version: 1.0 # Author: lax1dude -> INSERT 4 : 10 @ 4 +> INSERT 4 : 9 @ 4 + + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; + import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer; + import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DeferredStateManager; + import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.VertexMarkerState; -+ import net.lax1dude.eaglercraft.v1_8.opengl.ext.dynamiclights.DynamicLightsStateManager; > DELETE 3 @ 3 : 7 @@ -193,7 +192,7 @@ ~ private void renderModelAmbientOcclusionQuads(IBlockAccess blockAccessIn, IBlockState blockStateIn, ~ BlockPos blockPosIn, WorldRenderer worldRendererIn, List listQuadsIn, RenderEnv renderenv) { ~ boolean isDeferred = DeferredStateManager.isDeferredRenderer(); -~ boolean isDynamicLights = isDeferred || DynamicLightsStateManager.isDynamicLightsRender(); +~ boolean isDynamicLights = isDeferred;// || DynamicLightsStateManager.isDynamicLightsRender(); ~ float[] quadBounds = renderenv.getQuadBounds(); ~ BitSet boundsFlags = renderenv.getBoundsFlags(); ~ BlockModelRenderer.AmbientOcclusionFace aoFaceIn = renderenv.getAoFace(); @@ -249,7 +248,7 @@ ~ List listQuadsIn, RenderEnv renderenv) { ~ boolean isDeferred = DeferredStateManager.isDeferredRenderer(); -~ boolean isDynamicLights = isDeferred || DynamicLightsStateManager.isDynamicLightsRender(); +~ boolean isDynamicLights = isDeferred;// || DynamicLightsStateManager.isDynamicLightsRender(); ~ BitSet boundsFlags = renderenv.getBoundsFlags(); ~ float[] quadBounds = renderenv.getQuadBounds(); diff --git a/patches/minecraft/net/minecraft/client/renderer/RenderGlobal.edit.java b/patches/minecraft/net/minecraft/client/renderer/RenderGlobal.edit.java index 5de870cd..ee89575b 100644 --- a/patches/minecraft/net/minecraft/client/renderer/RenderGlobal.edit.java +++ b/patches/minecraft/net/minecraft/client/renderer/RenderGlobal.edit.java @@ -832,12 +832,13 @@ > DELETE 5 @ 5 : 6 -> CHANGE 155 : 159 @ 155 : 156 +> CHANGE 155 : 160 @ 155 : 156 ~ worldRendererIn.begin(7, -~ (DeferredStateManager.isDeferredRenderer() || DynamicLightsStateManager.isDynamicLightsRender()) -~ ? VertexFormat.BLOCK_SHADERS -~ : DefaultVertexFormats.BLOCK); +~ (DeferredStateManager +~ .isDeferredRenderer() /* || DynamicLightsStateManager.isDynamicLightsRender() */) +~ ? VertexFormat.BLOCK_SHADERS +~ : DefaultVertexFormats.BLOCK); > CHANGE 19 : 20 @ 19 : 20 diff --git a/patches/minecraft/net/minecraft/client/renderer/chunk/RenderChunk.edit.java b/patches/minecraft/net/minecraft/client/renderer/chunk/RenderChunk.edit.java index 0d6c66b8..32c23484 100644 --- a/patches/minecraft/net/minecraft/client/renderer/chunk/RenderChunk.edit.java +++ b/patches/minecraft/net/minecraft/client/renderer/chunk/RenderChunk.edit.java @@ -7,7 +7,7 @@ > DELETE 2 @ 2 : 5 -> CHANGE 3 : 11 @ 3 : 4 +> CHANGE 3 : 10 @ 3 : 4 ~ ~ import com.google.common.collect.Maps; @@ -16,7 +16,6 @@ ~ import net.lax1dude.eaglercraft.v1_8.opengl.VertexFormat; ~ import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer; ~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DeferredStateManager; -~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.dynamiclights.DynamicLightsStateManager; > DELETE 4 @ 4 : 7 @@ -186,7 +185,7 @@ > CHANGE 3 : 7 @ 3 : 4 ~ worldRendererIn.begin(7, -~ (DeferredStateManager.isDeferredRenderer() || DynamicLightsStateManager.isDynamicLightsRender()) +~ (DeferredStateManager.isDeferredRenderer() /* || DynamicLightsStateManager.isDynamicLightsRender() */) ~ ? VertexFormat.BLOCK_SHADERS ~ : DefaultVertexFormats.BLOCK); diff --git a/patches/minecraft/net/minecraft/client/renderer/entity/RenderFallingBlock.edit.java b/patches/minecraft/net/minecraft/client/renderer/entity/RenderFallingBlock.edit.java index 96956503..688c5d49 100644 --- a/patches/minecraft/net/minecraft/client/renderer/entity/RenderFallingBlock.edit.java +++ b/patches/minecraft/net/minecraft/client/renderer/entity/RenderFallingBlock.edit.java @@ -17,11 +17,10 @@ > DELETE 1 @ 1 : 4 -> CHANGE 28 : 32 @ 28 : 29 +> CHANGE 28 : 31 @ 28 : 29 -~ worldrenderer.begin(7, -~ (DeferredStateManager.isDeferredRenderer() -~ || DynamicLightsStateManager.isDynamicLightsRender()) ? VertexFormat.BLOCK_SHADERS -~ : DefaultVertexFormats.BLOCK); +~ worldrenderer.begin(7, (DeferredStateManager.isDeferredRenderer() +~ /* || DynamicLightsStateManager.isDynamicLightsRender() */) ? VertexFormat.BLOCK_SHADERS +~ : DefaultVertexFormats.BLOCK); > EOF diff --git a/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.edit.java b/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.edit.java index c64db9ca..7a955b37 100644 --- a/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.edit.java +++ b/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.edit.java @@ -21,7 +21,7 @@ ~ if (parGameProfile != null && parGameProfile.getId() != null) { ~ NetHandlerPlayClient netHandler = Minecraft.getMinecraft().getNetHandler(); ~ if (netHandler != null) { -~ resourcelocation = netHandler.getSkinCache().getSkin(parGameProfile).getResourceLocation(); +~ resourcelocation = netHandler.getTextureCache().getPlayerSkin(parGameProfile).getLocation(); > DELETE 2 @ 2 : 3 diff --git a/patches/minecraft/net/minecraft/entity/EntityLivingBase.edit.java b/patches/minecraft/net/minecraft/entity/EntityLivingBase.edit.java index b94f3e63..143db28a 100644 --- a/patches/minecraft/net/minecraft/entity/EntityLivingBase.edit.java +++ b/patches/minecraft/net/minecraft/entity/EntityLivingBase.edit.java @@ -5,14 +5,13 @@ # Version: 1.0 # Author: lax1dude -> INSERT 2 : 8 @ 2 +> INSERT 2 : 7 @ 2 -+ import com.carrotsearch.hppc.IntArrayList; + import com.carrotsearch.hppc.IntObjectHashMap; + import com.carrotsearch.hppc.IntObjectMap; + import com.carrotsearch.hppc.ObjectContainer; -+ import com.carrotsearch.hppc.cursors.IntObjectCursor; + import com.carrotsearch.hppc.cursors.ObjectCursor; ++ import com.carrotsearch.hppc.procedures.IntObjectProcedure; > CHANGE 2 : 5 @ 2 : 5 @@ -68,30 +67,30 @@ ~ this.activePotionsMap.put(potioneffect.getPotionID(), potioneffect); -> CHANGE 23 : 24 @ 23 : 24 +> CHANGE 23 : 26 @ 23 : 31 -~ IntArrayList deadPotionEffects = null; +~ if (!this.worldObj.isRemote) { +~ this.activePotionsMap.removeAll((integer, potioneffect) -> { +~ if (!potioneffect.onUpdate(this)) { -> CHANGE 1 : 4 @ 1 : 4 +> INSERT 1 : 4 @ 1 -~ for (IntObjectCursor cur : this.activePotionsMap) { -~ int integer = cur.key; -~ PotionEffect potioneffect = cur.value; ++ return true; ++ } else if (potioneffect.getDuration() % 600 == 0) { ++ this.onChangedPotionEffect(potioneffect, false); -> CHANGE 2 : 5 @ 2 : 3 +> CHANGE 1 : 9 @ 1 : 4 -~ if (deadPotionEffects == null) -~ deadPotionEffects = new IntArrayList(4); -~ deadPotionEffects.add(integer); +~ return false; +~ }); +~ } else { +~ this.activePotionsMap.forEach((IntObjectProcedure) (integer, potioneffect) -> { +~ if (potioneffect.onUpdate(this) && potioneffect.getDuration() % 600 == 0) { +~ this.onChangedPotionEffect(potioneffect, false); +~ } +~ }); -> INSERT 7 : 11 @ 7 - -+ if (deadPotionEffects != null) { -+ this.activePotionsMap.removeAll(deadPotionEffects); -+ } -+ - -> CHANGE 40 : 43 @ 40 : 43 +> CHANGE 42 : 45 @ 42 : 45 ~ ObjectContainer cc = this.activePotionsMap.values(); ~ int i = PotionHelper.calcPotionLiquidColor(cc); diff --git a/patches/minecraft/net/minecraft/entity/player/EntityPlayerMP.edit.java b/patches/minecraft/net/minecraft/entity/player/EntityPlayerMP.edit.java index 3a92d33a..7f7dbd3e 100644 --- a/patches/minecraft/net/minecraft/entity/player/EntityPlayerMP.edit.java +++ b/patches/minecraft/net/minecraft/entity/player/EntityPlayerMP.edit.java @@ -14,10 +14,12 @@ + import com.carrotsearch.hppc.cursors.IntCursor; + import com.carrotsearch.hppc.cursors.LongCursor; -> CHANGE 2 : 4 @ 2 : 4 +> CHANGE 2 : 6 @ 2 : 4 ~ import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile; ~ import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; +~ import net.lax1dude.eaglercraft.v1_8.sp.server.skins.PlayerTextureData; +~ > DELETE 17 @ 17 : 18 @@ -45,9 +47,10 @@ ~ private long playerLastActiveTime = EagRuntime.steadyTimeMillis(); -> INSERT 5 : 7 @ 5 +> INSERT 5 : 8 @ 5 + public byte[] updateCertificate = null; ++ public PlayerTextureData textureData = null; + public EaglercraftUUID clientBrandUUID = null; > CHANGE 87 : 88 @ 87 : 88 diff --git a/patches/minecraft/net/minecraft/event/ClickEvent.edit.java b/patches/minecraft/net/minecraft/event/ClickEvent.edit.java index 679072ed..e6283ab9 100644 --- a/patches/minecraft/net/minecraft/event/ClickEvent.edit.java +++ b/patches/minecraft/net/minecraft/event/ClickEvent.edit.java @@ -12,11 +12,7 @@ + import com.google.common.collect.Maps; + -> CHANGE 53 : 54 @ 53 : 54 - -~ CHANGE_PAGE("change_page", true), EAGLER_PLUGIN_DOWNLOAD("eagler_plugin_download", true); - -> CHANGE 23 : 26 @ 23 : 25 +> CHANGE 77 : 80 @ 77 : 79 ~ ClickEvent.Action[] types = values(); ~ for (int i = 0; i < types.length; ++i) { diff --git a/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.edit.java b/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.edit.java index 9a7c1604..369e6086 100644 --- a/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.edit.java +++ b/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.edit.java @@ -10,10 +10,14 @@ + import com.carrotsearch.hppc.IntShortHashMap; + import com.carrotsearch.hppc.IntShortMap; -> CHANGE 3 : 8 @ 3 : 7 +> CHANGE 3 : 12 @ 3 : 7 +~ +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants; ~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; -~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.message.InjectedMessageController; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.message.LegacyMessageController; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.message.MessageController; ~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; ~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketUpdateCertEAG; ~ @@ -28,13 +32,18 @@ > DELETE 25 @ 25 : 29 -> DELETE 35 @ 35 : 36 +> INSERT 33 : 34 @ 33 + ++ import net.minecraft.network.play.server.S3FPacketCustomPayload; + +> DELETE 2 @ 2 : 3 > DELETE 13 @ 13 : 14 -> INSERT 2 : 4 @ 2 +> INSERT 2 : 5 @ 2 + import net.lax1dude.eaglercraft.v1_8.sp.server.socket.IntegratedServerPlayerNetworkManager; ++ import net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol.ServerMessageHandler; + > DELETE 1 @ 1 : 3 @@ -62,34 +71,42 @@ > INSERT 4 : 6 @ 4 + private boolean hasDisconnected = false; -+ private GameProtocolMessageController eaglerMessageController = null; ++ private MessageController eaglerMessageController = null; > CHANGE 1 : 3 @ 1 : 2 ~ public NetHandlerPlayServer(MinecraftServer server, IntegratedServerPlayerNetworkManager networkManagerIn, -~ EntityPlayerMP playerIn) { +~ EntityPlayerMP playerIn, GamePluginMessageProtocol eaglerProtocol) { -> INSERT 7 : 28 @ 7 +> INSERT 5 : 15 @ 5 -+ public GameProtocolMessageController getEaglerMessageController() { ++ ServerMessageHandler handler = ServerMessageHandler.createServerHandler(eaglerProtocol.ver, this); ++ if (eaglerProtocol.ver >= 5) { ++ this.eaglerMessageController = new InjectedMessageController(eaglerProtocol, handler, ++ GamePluginMessageConstants.SERVER_TO_CLIENT, networkManagerIn::injectRawFrame); ++ networkManagerIn.setInjectedMessageController((InjectedMessageController) eaglerMessageController); ++ } else { ++ this.eaglerMessageController = new LegacyMessageController(eaglerProtocol, handler, ++ GamePluginMessageConstants.SERVER_TO_CLIENT, ++ (ch, msg) -> sendPacket(new S3FPacketCustomPayload(ch, msg))); ++ } + +> INSERT 2 : 18 @ 2 + ++ public MessageController getEaglerMessageController() { + return eaglerMessageController; + } + -+ public void setEaglerMessageController(GameProtocolMessageController eaglerMessageController) { ++ public void setEaglerMessageController(MessageController eaglerMessageController) { + this.eaglerMessageController = eaglerMessageController; + } + + public GamePluginMessageProtocol getEaglerMessageProtocol() { -+ return eaglerMessageController != null ? eaglerMessageController.protocol : null; ++ return eaglerMessageController != null ? eaglerMessageController.getProtocol() : null; + } + + public void sendEaglerMessage(GameMessagePacket packet) { -+ try { -+ eaglerMessageController.sendPacket(packet); -+ } catch (IOException e) { -+ logger.error("Failed to send eaglercraft plugin message packet: " + packet); -+ logger.error(e); -+ } ++ eaglerMessageController.sendPacket(packet); + } + @@ -268,10 +285,10 @@ + } + } + } -+ } else { ++ } else if (eaglerMessageController instanceof LegacyMessageController) { + try { -+ eaglerMessageController.handlePacket(c17packetcustompayload.getChannelName(), -+ c17packetcustompayload.getBufferData()); ++ ((LegacyMessageController) eaglerMessageController) ++ .handlePacket(c17packetcustompayload.getChannelName(), c17packetcustompayload.getBufferData()); + } catch (IOException e) { + logger.error("Couldn't read \"{}\" packet as an eaglercraft plugin message!", + c17packetcustompayload.getChannelName()); diff --git a/patches/minecraft/net/minecraft/network/PacketBuffer.edit.java b/patches/minecraft/net/minecraft/network/PacketBuffer.edit.java index ee221605..2bbbb9e8 100644 --- a/patches/minecraft/net/minecraft/network/PacketBuffer.edit.java +++ b/patches/minecraft/net/minecraft/network/PacketBuffer.edit.java @@ -138,6 +138,15 @@ > DELETE 20 @ 20 : 36 -> DELETE 88 @ 88 : 107 +> CHANGE 88 : 94 @ 88 : 90 + +~ public byte[] toBytes() { +~ int readerIndex = buf.readerIndex(); +~ int writerIndex = buf.writerIndex(); +~ byte[] bytes = new byte[writerIndex - readerIndex]; +~ buf.getBytes(readerIndex, bytes); +~ return bytes; + +> DELETE 2 @ 2 : 17 > EOF diff --git a/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.edit.java b/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.edit.java index 779ac883..853b505c 100644 --- a/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.edit.java +++ b/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.edit.java @@ -30,14 +30,13 @@ + import net.minecraft.util.ChatComponentText; -> CHANGE 12 : 22 @ 12 : 14 +> CHANGE 12 : 21 @ 12 : 14 -~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants; ~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; -~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController; ~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketUpdateCertEAG; ~ import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer; ~ import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB; +~ import net.lax1dude.eaglercraft.v1_8.sp.server.skins.PlayerTextureData; ~ import net.lax1dude.eaglercraft.v1_8.sp.server.socket.IntegratedServerPlayerNetworkManager; ~ import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService; ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; @@ -69,20 +68,18 @@ > CHANGE 2 : 6 @ 2 : 8 ~ public void initializeConnectionToPlayer(IntegratedServerPlayerNetworkManager netManager, EntityPlayerMP playerIn, -~ int protocolVersion, EaglercraftUUID clientBrandUUID) { +~ GamePluginMessageProtocol protocolVersion, PlayerTextureData textureData, EaglercraftUUID clientBrandUUID) { +~ playerIn.textureData = textureData; ~ playerIn.clientBrandUUID = clientBrandUUID; -~ GameProfile gameprofile1 = playerIn.getGameProfile(); > CHANGE 3 : 4 @ 3 : 7 ~ String s1 = "channel:" + netManager.playerChannel; -> INSERT 8 : 12 @ 8 +> CHANGE 7 : 9 @ 7 : 8 -+ nethandlerplayserver.setEaglerMessageController(new GameProtocolMessageController( -+ GamePluginMessageProtocol.getByVersion(protocolVersion), GamePluginMessageConstants.SERVER_TO_CLIENT, -+ GameProtocolMessageController.createServerHandler(protocolVersion, nethandlerplayserver), -+ (ch, msg) -> nethandlerplayserver.sendPacket(new S3FPacketCustomPayload(ch, msg)))); +~ NetHandlerPlayServer nethandlerplayserver = new NetHandlerPlayServer(this.mcServer, netManager, playerIn, +~ protocolVersion); > DELETE 4 @ 4 : 6 @@ -142,10 +139,8 @@ ~ this.playerStatFiles.remove(entityplayermp.getName()); -> INSERT 2 : 9 @ 2 +> INSERT 2 : 7 @ 2 -+ ((EaglerMinecraftServer) mcServer).getSkinService().unregisterPlayer(uuid); -+ ((EaglerMinecraftServer) mcServer).getCapeService().unregisterPlayer(uuid); + IntegratedVoiceService vcs = ((EaglerMinecraftServer) mcServer).getVoiceService(); + if (vcs != null) { + vcs.handlePlayerLoggedOut(playerIn); diff --git a/patches/minecraft/net/minecraft/server/network/NetHandlerLoginServer.edit.java b/patches/minecraft/net/minecraft/server/network/NetHandlerLoginServer.edit.java index 7601a848..dc5f3509 100644 --- a/patches/minecraft/net/minecraft/server/network/NetHandlerLoginServer.edit.java +++ b/patches/minecraft/net/minecraft/server/network/NetHandlerLoginServer.edit.java @@ -5,14 +5,16 @@ # Version: 1.0 # Author: lax1dude -> CHANGE 3 : 9 @ 3 : 15 +> CHANGE 3 : 11 @ 3 : 15 ~ import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile; +~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; ~ import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache; ~ import net.lax1dude.eaglercraft.v1_8.EaglerInputStream; ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion; ~ import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer; +~ import net.lax1dude.eaglercraft.v1_8.sp.server.skins.IntegratedTexturePackets; > CHANGE 1 : 2 @ 1 : 2 @@ -62,19 +64,14 @@ > DELETE 2 @ 2 : 3 -> CHANGE 11 : 23 @ 11 : 12 +> CHANGE 11 : 18 @ 11 : 12 -~ this.field_181025_l, this.selectedProtocol, this.clientBrandUUID); -~ ((EaglerMinecraftServer) field_181025_l.mcServer).getSkinService() -~ .processLoginPacket(this.loginSkinPacket, field_181025_l, 3); // singleplayer always sends V3 -~ // skin in handshake -~ if (this.loginCapePacket != null) { -~ ((EaglerMinecraftServer) field_181025_l.mcServer).getCapeService() -~ .processLoginPacket(this.loginCapePacket, field_181025_l); -~ } +~ this.field_181025_l, GamePluginMessageProtocol.getByVersion(this.selectedProtocol), +~ IntegratedTexturePackets.handleTextureData(this.loginSkinPacket, this.loginCapePacket), +~ this.clientBrandUUID); ~ IntegratedVoiceService svc = ((EaglerMinecraftServer) field_181025_l.mcServer).getVoiceService(); ~ if (svc != null) { -~ svc.handlePlayerLoggedIn(entityplayermp); +~ svc.handlePlayerLoggedIn(this.field_181025_l); ~ } > CHANGE 23 : 24 @ 23 : 29 @@ -86,18 +83,13 @@ ~ this.networkManager.sendPacket(new S02PacketLoginSuccess(this.loginGameProfile, this.selectedProtocol)); ~ this.networkManager.setConnectionState(EnumConnectionState.PLAY); -> CHANGE 6 : 20 @ 6 : 8 +> CHANGE 6 : 15 @ 6 : 8 ~ entityplayermp = this.server.getConfigurationManager().createPlayerForUser(this.loginGameProfile); ~ this.server.getConfigurationManager().initializeConnectionToPlayer(this.networkManager, entityplayermp, -~ this.selectedProtocol, this.clientBrandUUID); -~ ((EaglerMinecraftServer) entityplayermp.mcServer).getSkinService() -~ .processLoginPacket(this.loginSkinPacket, entityplayermp, 3); // singleplayer always sends V3 -~ // skin in handshake -~ if (this.loginCapePacket != null) { -~ ((EaglerMinecraftServer) entityplayermp.mcServer).getCapeService() -~ .processLoginPacket(this.loginCapePacket, entityplayermp); -~ } +~ GamePluginMessageProtocol.getByVersion(this.selectedProtocol), +~ IntegratedTexturePackets.handleTextureData(this.loginSkinPacket, this.loginCapePacket), +~ this.clientBrandUUID); ~ IntegratedVoiceService svc = ((EaglerMinecraftServer) entityplayermp.mcServer).getVoiceService(); ~ if (svc != null) { ~ svc.handlePlayerLoggedIn(entityplayermp); @@ -117,7 +109,7 @@ ~ int protocolCount = dis.readUnsignedShort(); ~ for (int i = 0; i < protocolCount; ++i) { ~ int p = dis.readUnsignedShort(); -~ if ((p == 3 || p == 4) && p > maxSupported) { +~ if ((p == 3 || p == 4 || p == 5) && p > maxSupported) { ~ maxSupported = p; ~ } ~ } diff --git a/patches/minecraft/net/minecraft/util/StringTranslate.edit.java b/patches/minecraft/net/minecraft/util/StringTranslate.edit.java index f3a23486..f198a8ad 100644 --- a/patches/minecraft/net/minecraft/util/StringTranslate.edit.java +++ b/patches/minecraft/net/minecraft/util/StringTranslate.edit.java @@ -38,14 +38,13 @@ ~ private StringTranslate() { ~ } -> CHANGE 1 : 25 @ 1 : 9 +> CHANGE 1 : 24 @ 1 : 9 ~ public static void initClient() { ~ try (InputStream inputstream = EagRuntime.getRequiredResourceStream("/assets/minecraft/lang/en_US.lang")) { ~ initServer(IOUtils.readLines(inputstream, StandardCharsets.UTF_8)); ~ fallbackInstance = new StringTranslate(); ~ fallbackInstance.replaceWith(instance.languageList); -~ SingleplayerServerController.updateLocale(dump()); ~ } catch (IOException e) { ~ EagRuntime.debugPrintStackTrace(e); ~ } @@ -75,9 +74,10 @@ ~ public static void replaceWith(Map parMap) { -> CHANGE 2 : 3 @ 2 : 3 +> CHANGE 2 : 4 @ 2 : 3 ~ instance.lastUpdateTimeInMilliseconds = EagRuntime.steadyTimeMillis(); +~ SingleplayerServerController.updateLocale(dump()); > CHANGE 2 : 3 @ 2 : 3 diff --git a/patches/minecraft/net/minecraft/world/SpawnerAnimals.edit.java b/patches/minecraft/net/minecraft/world/SpawnerAnimals.edit.java index 618081e5..07e23c4c 100644 --- a/patches/minecraft/net/minecraft/world/SpawnerAnimals.edit.java +++ b/patches/minecraft/net/minecraft/world/SpawnerAnimals.edit.java @@ -37,15 +37,13 @@ ~ byte b0 = (byte) spawnHostileMobs.getMinecraftServer().getConfigurationManager().getViewDistance(); -> CHANGE 4 : 9 @ 4 : 6 +> CHANGE 4 : 7 @ 4 : 5 ~ int cx = l + j; ~ int cz = i1 + k; ~ long chunkcoordintpair = ChunkCoordIntPair.chunkXZ2Int(cx, cz); -~ if (!this.eligibleChunksForSpawning.contains(chunkcoordintpair) -~ && spawnHostileMobs.theChunkProviderServer.chunkExists(cx, cz)) { -> CHANGE 13 : 16 @ 13 : 14 +> CHANGE 14 : 17 @ 14 : 15 ~ EnumCreatureType[] types = EnumCreatureType._VALUES; ~ for (int m = 0; m < types.length; ++m) { diff --git a/patches/resources/assets/minecraft/lang/en_US.edit.lang b/patches/resources/assets/minecraft/lang/en_US.edit.lang index 65183993..babd68fe 100644 --- a/patches/resources/assets/minecraft/lang/en_US.edit.lang +++ b/patches/resources/assets/minecraft/lang/en_US.edit.lang @@ -16,7 +16,7 @@ ~ eaglercraft.resourcePack.load.loading=Loading resource pack... ~ eaglercraft.resourcePack.load.deleting=Deleting resource pack... -> INSERT 1 : 246 @ 1 +> INSERT 1 : 247 @ 1 + eaglercraft.gui.exitKey=Use '%s' to close this screen! + eaglercraft.gui.exitKeyRetarded=Use Backtick (`) to close this screen! @@ -201,8 +201,9 @@ + eaglercraft.shaders.gui.option.LIGHT_SHAFTS.label=God Rays + + eaglercraft.shaders.gui.option.LIGHT_SHAFTS.desc.0=Render god rays (light shafts) for sunlight and moonlight shadows -+ eaglercraft.shaders.gui.option.LIGHT_SHAFTS.desc.2=ON: render god rays (slower) -+ eaglercraft.shaders.gui.option.LIGHT_SHAFTS.desc.3=OFF: disable god rays (faster) ++ eaglercraft.shaders.gui.option.LIGHT_SHAFTS.desc.2=This shader tends to look unpleasent if the render distance is greater than the shadow map size ++ eaglercraft.shaders.gui.option.LIGHT_SHAFTS.desc.4=ON: render god rays (slower) ++ eaglercraft.shaders.gui.option.LIGHT_SHAFTS.desc.5=OFF: disable god rays (faster) + + eaglercraft.shaders.gui.option.SCREEN_SPACE_REFLECTIONS.label=Raytracing + @@ -264,7 +265,7 @@ + eaglercraft.command.clientStub=This command is client side! + -> INSERT 163 : 574 @ 163 +> INSERT 163 : 578 @ 163 + eaglercraft.singleplayer.busy.killTask=Cancel Task + eaglercraft.singleplayer.busy.cancelWarning=Are you sure? @@ -594,12 +595,16 @@ + eaglercraft.fallbackWebViewScreen.openButton=Open + eaglercraft.fallbackWebViewScreen.exitButton=Exit + -+ eaglercraft.webviewPhishingWaring.title=WARNING!!! -+ eaglercraft.webviewPhishingWaring.text0=If you see a login page, think before you enter a password -+ eaglercraft.webviewPhishingWaring.text1=Passwords can be stolen by the owner of this server or website -+ eaglercraft.webviewPhishingWaring.text2=Do not log in to accounts you don't want hackers to steal -+ eaglercraft.webviewPhishingWaring.dontShowAgain=Do not show this message again -+ eaglercraft.webviewPhishingWaring.continue=Continue ++ eaglercraft.webviewPhishingWarning.title=WARNING!!! ++ eaglercraft.webviewPhishingWarning.text0=If you see a login page, think before you enter a password ++ eaglercraft.webviewPhishingWarning.text1=Passwords can be stolen by the owner of this server or website ++ eaglercraft.webviewPhishingWarning.text2=Do not log in to accounts you don't want hackers to steal ++ eaglercraft.webviewPhishingWarning.dontShowAgain=Do not show this message again ++ eaglercraft.webviewPhishingWarning.continue=Continue ++ ++ eaglercraft.webviewDisplayWarning.title=WebView Warning ++ eaglercraft.webviewDisplayWarning.text0=This server is attempting to display HTML content ++ eaglercraft.webviewDisplayWarning.text1=Would you like to continue? + + eaglercraft.notifications.title=Notifications + eaglercraft.notifications.priority=Priority: %s diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java index 755f574c..5f81fe19 100644 --- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java +++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java @@ -40,6 +40,7 @@ class OpenGLObjects { static class VertexArrayGL implements IVertexArrayGL { final int ptr; + int enabled; VertexArrayGL(int ptr) { this.ptr = ptr; @@ -53,7 +54,22 @@ class OpenGLObjects { public void free() { PlatformOpenGL._wglDeleteVertexArrays(this); } - + + @Override + public int getBits() { + return enabled; + } + + @Override + public void setBit(int bit) { + enabled |= bit; + } + + @Override + public void unsetBit(int bit) { + enabled &= ~bit; + } + } static class TextureGL implements ITextureGL { diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java index 5faff7ad..f53135c9 100644 --- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java +++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java @@ -580,7 +580,7 @@ public class PlatformInput { } public static boolean contextLost() { - return glfwGetWindowAttrib(win, GLFW_ICONIFIED) == GLFW_TRUE; + return false; } public static void setFunctionKeyModifier(int key) { diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java index 63cc517f..f3dab7d2 100644 --- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java +++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java @@ -101,7 +101,11 @@ public class PlatformRuntime { IEaglerFilesystem resourcePackFilesystem = Filesystem.getHandleFor(getClientConfigAdapter().getResourcePacksDB()); VFile2.setPrimaryFilesystem(resourcePackFilesystem); EaglerFolderResourcePack.setSupported(true); - + + if (glfwPlatformSupported(GLFW_PLATFORM_X11)) { + glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11); + } + if(requestedANGLEPlatform != EnumPlatformANGLE.DEFAULT) { logger.info("Setting ANGLE Platform: {}", requestedANGLEPlatform.name); glfwInitHint(GLFW_ANGLE_PLATFORM_TYPE, requestedANGLEPlatform.eglEnum); diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java index e016ef26..5a379929 100644 --- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java +++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java @@ -65,6 +65,14 @@ public class PlatformVoiceClient { } + public static void makePeerGlobal(EaglercraftUUID peerId) { + + } + + public static void makePeerProximity(EaglercraftUUID peerId) { + + } + public static void tickVoiceClient() { } diff --git a/sources/main/java/com/carrotsearch/hppc/AbstractByteCollection.java b/sources/main/java/com/carrotsearch/hppc/AbstractByteCollection.java deleted file mode 100644 index ed184354..00000000 --- a/sources/main/java/com/carrotsearch/hppc/AbstractByteCollection.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ByteCursor; -import com.carrotsearch.hppc.predicates.BytePredicate; -import java.util.Arrays; - -/** Common superclass for collections. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "AbstractKTypeCollection.java") -abstract class AbstractByteCollection implements ByteCollection { - /** Default implementation uses a predicate for removal. */ - @Override - public int removeAll(final ByteLookupContainer c) { - return this.removeAll(c::contains); - } - - /** Default implementation uses a predicate for retaining. */ - @Override - public int retainAll(final ByteLookupContainer c) { - // We know c holds sub-types of byte and we're not modifying c, so go unchecked. - return this.removeAll(k -> !c.contains(k)); - } - - /** - * Default implementation redirects to {@link #removeAll(BytePredicate)} and negates the - * predicate. - */ - @Override - public int retainAll(final BytePredicate predicate) { - return removeAll(value -> !predicate.apply(value)); - } - - /** Default implementation of copying to an array. */ - @Override - public byte[] toArray() { - - byte[] array = (new byte[size()]); - int i = 0; - for (ByteCursor c : this) { - array[i++] = c.value; - } - return array; - } - - /** Convert the contents of this container to a human-friendly string. */ - @Override - public String toString() { - return Arrays.toString(this.toArray()); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/AbstractCharCollection.java b/sources/main/java/com/carrotsearch/hppc/AbstractCharCollection.java deleted file mode 100644 index 5ecdbb55..00000000 --- a/sources/main/java/com/carrotsearch/hppc/AbstractCharCollection.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharCursor; -import com.carrotsearch.hppc.predicates.CharPredicate; -import java.util.Arrays; - -/** Common superclass for collections. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "AbstractKTypeCollection.java") -abstract class AbstractCharCollection implements CharCollection { - /** Default implementation uses a predicate for removal. */ - @Override - public int removeAll(final CharLookupContainer c) { - return this.removeAll(c::contains); - } - - /** Default implementation uses a predicate for retaining. */ - @Override - public int retainAll(final CharLookupContainer c) { - // We know c holds sub-types of char and we're not modifying c, so go unchecked. - return this.removeAll(k -> !c.contains(k)); - } - - /** - * Default implementation redirects to {@link #removeAll(CharPredicate)} and negates the - * predicate. - */ - @Override - public int retainAll(final CharPredicate predicate) { - return removeAll(value -> !predicate.apply(value)); - } - - /** Default implementation of copying to an array. */ - @Override - public char[] toArray() { - - char[] array = (new char[size()]); - int i = 0; - for (CharCursor c : this) { - array[i++] = c.value; - } - return array; - } - - /** Convert the contents of this container to a human-friendly string. */ - @Override - public String toString() { - return Arrays.toString(this.toArray()); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/AbstractDoubleCollection.java b/sources/main/java/com/carrotsearch/hppc/AbstractDoubleCollection.java deleted file mode 100644 index 2bb296ff..00000000 --- a/sources/main/java/com/carrotsearch/hppc/AbstractDoubleCollection.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.DoubleCursor; -import com.carrotsearch.hppc.predicates.DoublePredicate; -import java.util.Arrays; - -/** Common superclass for collections. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "AbstractKTypeCollection.java") -abstract class AbstractDoubleCollection implements DoubleCollection { - /** Default implementation uses a predicate for removal. */ - @Override - public int removeAll(final DoubleLookupContainer c) { - return this.removeAll(c::contains); - } - - /** Default implementation uses a predicate for retaining. */ - @Override - public int retainAll(final DoubleLookupContainer c) { - // We know c holds sub-types of double and we're not modifying c, so go unchecked. - return this.removeAll(k -> !c.contains(k)); - } - - /** - * Default implementation redirects to {@link #removeAll(DoublePredicate)} and negates the - * predicate. - */ - @Override - public int retainAll(final DoublePredicate predicate) { - return removeAll(value -> !predicate.apply(value)); - } - - /** Default implementation of copying to an array. */ - @Override - public double[] toArray() { - - double[] array = (new double[size()]); - int i = 0; - for (DoubleCursor c : this) { - array[i++] = c.value; - } - return array; - } - - /** Convert the contents of this container to a human-friendly string. */ - @Override - public String toString() { - return Arrays.toString(this.toArray()); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/AbstractFloatCollection.java b/sources/main/java/com/carrotsearch/hppc/AbstractFloatCollection.java deleted file mode 100644 index 089086f8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/AbstractFloatCollection.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.FloatCursor; -import com.carrotsearch.hppc.predicates.FloatPredicate; -import java.util.Arrays; - -/** Common superclass for collections. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "AbstractKTypeCollection.java") -abstract class AbstractFloatCollection implements FloatCollection { - /** Default implementation uses a predicate for removal. */ - @Override - public int removeAll(final FloatLookupContainer c) { - return this.removeAll(c::contains); - } - - /** Default implementation uses a predicate for retaining. */ - @Override - public int retainAll(final FloatLookupContainer c) { - // We know c holds sub-types of float and we're not modifying c, so go unchecked. - return this.removeAll(k -> !c.contains(k)); - } - - /** - * Default implementation redirects to {@link #removeAll(FloatPredicate)} and negates the - * predicate. - */ - @Override - public int retainAll(final FloatPredicate predicate) { - return removeAll(value -> !predicate.apply(value)); - } - - /** Default implementation of copying to an array. */ - @Override - public float[] toArray() { - - float[] array = (new float[size()]); - int i = 0; - for (FloatCursor c : this) { - array[i++] = c.value; - } - return array; - } - - /** Convert the contents of this container to a human-friendly string. */ - @Override - public String toString() { - return Arrays.toString(this.toArray()); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/AbstractIntCollection.java b/sources/main/java/com/carrotsearch/hppc/AbstractIntCollection.java deleted file mode 100644 index e9ae748d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/AbstractIntCollection.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntCursor; -import com.carrotsearch.hppc.predicates.IntPredicate; -import java.util.Arrays; - -/** Common superclass for collections. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "AbstractKTypeCollection.java") -abstract class AbstractIntCollection implements IntCollection { - /** Default implementation uses a predicate for removal. */ - @Override - public int removeAll(final IntLookupContainer c) { - return this.removeAll(c::contains); - } - - /** Default implementation uses a predicate for retaining. */ - @Override - public int retainAll(final IntLookupContainer c) { - // We know c holds sub-types of int and we're not modifying c, so go unchecked. - return this.removeAll(k -> !c.contains(k)); - } - - /** - * Default implementation redirects to {@link #removeAll(IntPredicate)} and negates the predicate. - */ - @Override - public int retainAll(final IntPredicate predicate) { - return removeAll(value -> !predicate.apply(value)); - } - - /** Default implementation of copying to an array. */ - @Override - public int[] toArray() { - - int[] array = (new int[size()]); - int i = 0; - for (IntCursor c : this) { - array[i++] = c.value; - } - return array; - } - - /** Convert the contents of this container to a human-friendly string. */ - @Override - public String toString() { - return Arrays.toString(this.toArray()); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/AbstractIterator.java b/sources/main/java/com/carrotsearch/hppc/AbstractIterator.java deleted file mode 100644 index 78951402..00000000 --- a/sources/main/java/com/carrotsearch/hppc/AbstractIterator.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** Simplifies the implementation of iterators a bit. Modeled loosely after Google Guava's API. */ -public abstract class AbstractIterator implements Iterator { - private static final int NOT_CACHED = 0; - private static final int CACHED = 1; - private static final int AT_END = 2; - - /** Current iterator state. */ - private int state = NOT_CACHED; - - /** The next element to be returned from {@link #next()} if fetched. */ - private E nextElement; - - /** {@inheritDoc} */ - @Override - public boolean hasNext() { - if (state == NOT_CACHED) { - state = CACHED; - nextElement = fetch(); - } - return state == CACHED; - } - - /** {@inheritDoc} */ - @Override - public E next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - - state = NOT_CACHED; - return nextElement; - } - - /** Default implementation throws {@link UnsupportedOperationException}. */ - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - /** - * Fetch next element. The implementation must return {@link #done()} when all elements have been - * fetched. - * - * @return Returns the next value for the iterator or chain-calls {@link #done()}. - */ - protected abstract E fetch(); - - /** - * Call when done. - * - * @return Returns a unique sentinel value to indicate end-of-iteration. - */ - protected final E done() { - state = AT_END; - return null; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/AbstractLongCollection.java b/sources/main/java/com/carrotsearch/hppc/AbstractLongCollection.java deleted file mode 100644 index 914bc36e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/AbstractLongCollection.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongCursor; -import com.carrotsearch.hppc.predicates.LongPredicate; -import java.util.Arrays; - -/** Common superclass for collections. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "AbstractKTypeCollection.java") -abstract class AbstractLongCollection implements LongCollection { - /** Default implementation uses a predicate for removal. */ - @Override - public int removeAll(final LongLookupContainer c) { - return this.removeAll(c::contains); - } - - /** Default implementation uses a predicate for retaining. */ - @Override - public int retainAll(final LongLookupContainer c) { - // We know c holds sub-types of long and we're not modifying c, so go unchecked. - return this.removeAll(k -> !c.contains(k)); - } - - /** - * Default implementation redirects to {@link #removeAll(LongPredicate)} and negates the - * predicate. - */ - @Override - public int retainAll(final LongPredicate predicate) { - return removeAll(value -> !predicate.apply(value)); - } - - /** Default implementation of copying to an array. */ - @Override - public long[] toArray() { - - long[] array = (new long[size()]); - int i = 0; - for (LongCursor c : this) { - array[i++] = c.value; - } - return array; - } - - /** Convert the contents of this container to a human-friendly string. */ - @Override - public String toString() { - return Arrays.toString(this.toArray()); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/AbstractObjectCollection.java b/sources/main/java/com/carrotsearch/hppc/AbstractObjectCollection.java deleted file mode 100644 index 1a841f62..00000000 --- a/sources/main/java/com/carrotsearch/hppc/AbstractObjectCollection.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectCursor; -import com.carrotsearch.hppc.predicates.ObjectPredicate; -import java.util.Arrays; - -/** Common superclass for collections. */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "AbstractKTypeCollection.java") -abstract class AbstractObjectCollection implements ObjectCollection { - /** Default implementation uses a predicate for removal. */ - @Override - public int removeAll(final ObjectLookupContainer c) { - return this.removeAll(c::contains); - } - - /** Default implementation uses a predicate for retaining. */ - @Override - public int retainAll(final ObjectLookupContainer c) { - // We know c holds sub-types of Object and we're not modifying c, so go unchecked. - return this.removeAll(k -> !c.contains(k)); - } - - /** - * Default implementation redirects to {@link #removeAll(ObjectPredicate)} and negates the - * predicate. - */ - @Override - public int retainAll(final ObjectPredicate predicate) { - return removeAll(value -> !predicate.apply(value)); - } - - /** Default implementation of copying to an array. */ - @Override - public Object[] toArray() { - - KType[] array = ((KType[]) new Object[size()]); - int i = 0; - for (ObjectCursor c : this) { - array[i++] = c.value; - } - return array; - } - - public T[] toArray(Class componentClass) { - final int size = size(); - final T[] array = (T[]) java.lang.reflect.Array.newInstance(componentClass, size); - int i = 0; - for (ObjectCursor c : this) { - array[i++] = (T) c.value; - } - return array; - } - - /** Convert the contents of this container to a human-friendly string. */ - @Override - public String toString() { - return Arrays.toString(this.toArray()); - } - - protected boolean equals(Object v1, Object v2) { - return (v1 == v2) || (v1 != null && v1.equals(v2)); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/AbstractShortCollection.java b/sources/main/java/com/carrotsearch/hppc/AbstractShortCollection.java deleted file mode 100644 index e78dbe11..00000000 --- a/sources/main/java/com/carrotsearch/hppc/AbstractShortCollection.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortCursor; -import com.carrotsearch.hppc.predicates.ShortPredicate; -import java.util.Arrays; - -/** Common superclass for collections. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "AbstractKTypeCollection.java") -abstract class AbstractShortCollection implements ShortCollection { - /** Default implementation uses a predicate for removal. */ - @Override - public int removeAll(final ShortLookupContainer c) { - return this.removeAll(c::contains); - } - - /** Default implementation uses a predicate for retaining. */ - @Override - public int retainAll(final ShortLookupContainer c) { - // We know c holds sub-types of short and we're not modifying c, so go unchecked. - return this.removeAll(k -> !c.contains(k)); - } - - /** - * Default implementation redirects to {@link #removeAll(ShortPredicate)} and negates the - * predicate. - */ - @Override - public int retainAll(final ShortPredicate predicate) { - return removeAll(value -> !predicate.apply(value)); - } - - /** Default implementation of copying to an array. */ - @Override - public short[] toArray() { - - short[] array = (new short[size()]); - int i = 0; - for (ShortCursor c : this) { - array[i++] = c.value; - } - return array; - } - - /** Convert the contents of this container to a human-friendly string. */ - @Override - public String toString() { - return Arrays.toString(this.toArray()); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/Accountable.java b/sources/main/java/com/carrotsearch/hppc/Accountable.java deleted file mode 100644 index 44aefc9b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/Accountable.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -/** - * Anything that could be accounted for memory usage - * - *

Partly forked from Lucene tag releases/lucene-solr/8.5.1 - */ -public interface Accountable { - /** - * Allocated memory estimation - * - * @return Ram allocated in bytes - */ - long ramBytesAllocated(); - - /** - * Bytes that is actually been used - * - * @return Ram used in bytes - */ - long ramBytesUsed(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ArraySizingStrategy.java b/sources/main/java/com/carrotsearch/hppc/ArraySizingStrategy.java deleted file mode 100644 index b541c56f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ArraySizingStrategy.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -/** Resizing (growth) strategy for array-backed buffers. */ -public interface ArraySizingStrategy extends Accountable { - /** - * @param currentBufferLength Current size of the array (buffer). This number should comply with - * the strategy's policies (it is a result of initial rounding or further growCalls). It can - * also be zero, indicating the growth from an empty buffer. - * @param elementsCount Number of elements stored in the buffer. - * @param expectedAdditions Expected number of additions (resize hint). - * @return Must return a new size at least as big as to hold - * elementsCount + expectedAdditions. - * @throws BufferAllocationException If the sizing strategy cannot grow the buffer (for example - * due to constraints or memory limits). - */ - int grow(int currentBufferLength, int elementsCount, int expectedAdditions) - throws BufferAllocationException; -} diff --git a/sources/main/java/com/carrotsearch/hppc/BitMixer.java b/sources/main/java/com/carrotsearch/hppc/BitMixer.java deleted file mode 100644 index 136c12f9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/BitMixer.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -/** - * Bit mixing utilities. The purpose of these methods is to evenly distribute key space over int32 - * range. - */ -public final class BitMixer { - - // Don't bother mixing very small key domains much. - public static int mix(byte key) { - return key * PHI_C32; - } - - public static int mix(short key) { - return mixPhi(key); - } - - public static int mix(char key) { - return mixPhi(key); - } - - // Better mix for larger key domains. - public static int mix(int key) { - return mix32(key); - } - - public static int mix(float key) { - return mix32(Float.floatToIntBits(key)); - } - - public static int mix(double key) { - return (int) mix64(Double.doubleToLongBits(key)); - } - - public static int mix(long key) { - return (int) mix64(key); - } - - public static int mix(Object key) { - return key == null ? 0 : mix32(key.hashCode()); - } - - /** MH3's plain finalization step. */ - public static int mix32(int k) { - k = (k ^ (k >>> 16)) * 0x85ebca6b; - k = (k ^ (k >>> 13)) * 0xc2b2ae35; - return k ^ (k >>> 16); - } - - /** - * Computes David Stafford variant 9 of 64bit mix function (MH3 finalization step, with different - * shifts and constants). - * - *

Variant 9 is picked because it contains two 32-bit shifts which could be possibly optimized - * into better machine code. - * - * @see "http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html" - */ - public static long mix64(long z) { - z = (z ^ (z >>> 32)) * 0x4cd6944c5cc20b6dL; - z = (z ^ (z >>> 29)) * 0xfc12c5b19d3259e9L; - return z ^ (z >>> 32); - } - - /* - * Golden ratio bit mixers. - */ - - private static final int PHI_C32 = 0x9e3779b9; - private static final long PHI_C64 = 0x9e3779b97f4a7c15L; - - public static int mixPhi(byte k) { - final int h = k * PHI_C32; - return h ^ (h >>> 16); - } - - public static int mixPhi(char k) { - final int h = k * PHI_C32; - return h ^ (h >>> 16); - } - - public static int mixPhi(short k) { - final int h = k * PHI_C32; - return h ^ (h >>> 16); - } - - public static int mixPhi(int k) { - final int h = k * PHI_C32; - return h ^ (h >>> 16); - } - - public static int mixPhi(float k) { - final int h = Float.floatToIntBits(k) * PHI_C32; - return h ^ (h >>> 16); - } - - public static int mixPhi(double k) { - final long h = Double.doubleToLongBits(k) * PHI_C64; - return (int) (h ^ (h >>> 32)); - } - - public static int mixPhi(long k) { - final long h = k * PHI_C64; - return (int) (h ^ (h >>> 32)); - } - - public static int mixPhi(Object k) { - final int h = (k == null ? 0 : k.hashCode() * PHI_C32); - return h ^ (h >>> 16); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/BitSet.java b/sources/main/java/com/carrotsearch/hppc/BitSet.java deleted file mode 100644 index 7f8a94bc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/BitSet.java +++ /dev/null @@ -1,952 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntCursor; -import com.carrotsearch.hppc.cursors.LongCursor; -import com.carrotsearch.hppc.predicates.IntPredicate; -import com.carrotsearch.hppc.predicates.LongPredicate; -import com.carrotsearch.hppc.procedures.IntProcedure; -import com.carrotsearch.hppc.procedures.LongProcedure; -import java.util.*; - -/** - * An "open" BitSet implementation that allows direct access to the array of words storing the bits. - * - *

Unlike {@link java.util.BitSet}, the fact that bits are packed into an array of longs is part - * of the interface. This allows efficient implementation of other algorithms by someone other than - * the author. It also allows one to efficiently implement alternate serialization or interchange - * formats. - * - *

The index range for a bitset can easily exceed positive int range in Java - * (0x7fffffff), so many methods in this class accept or return a long. There are - * adapter methods that return views compatible with {@link LongLookupContainer} and {@link - * IntLookupContainer} interfaces. - * - * @see #asIntLookupContainer() - * @see #asLongLookupContainer() - */ -public class BitSet implements Cloneable { - /** The initial default number of bits. */ - private static final long DEFAULT_NUM_BITS = 64; - - /** Internal representation of bits in this bit set. */ - public long[] bits; - - /** The number of words (longs) used in the {@link #bits} array. */ - public int wlen; - - /** Constructs a bit set with the default capacity. */ - public BitSet() { - this(DEFAULT_NUM_BITS); - } - - /** - * Constructs an BitSet large enough to hold numBits. - * - * @param numBits Number of bits - */ - public BitSet(long numBits) { - bits = new long[bits2words(numBits)]; - wlen = bits.length; - } - - /** - * Constructs an BitSet from an existing long[]. - * - *

The first 64 bits are in long[0], with bit index 0 at the least significant bit, and bit - * index 63 at the most significant. Given a bit index, the word containing it is long[index/64], - * and it is at bit number index%64 within that word. - * - *

numWords are the number of elements in the array that contain set bits (non-zero longs). - * numWords should be <= bits.length, and any existing words in the array at position >= - * numWords should be zero. - * - * @param bits underlying bits buffer - * @param numWords the number of elements in the array that contain set bits - */ - public BitSet(long[] bits, int numWords) { - this.bits = bits; - this.wlen = numWords; - } - - /** - * Static constructor-like method similar to other (generic) collections. - * - * @return New instance. - */ - public static BitSet newInstance() { - return new BitSet(); - } - - /** - * @return Returns an iterator over all set bits of this bitset. The iterator should be faster - * than using a loop around {@link #nextSetBit(int)}. - */ - public BitSetIterator iterator() { - return new BitSetIterator(bits, wlen); - } - - /** - * @return Returns the current capacity in bits (1 greater than the index of the last bit). - */ - public long capacity() { - return bits.length << 6; - } - - /** - * @see #cardinality() - * @see java.util.BitSet#size() - * @return Returns the current capacity of this set. Included for compatibility. This is - * not equal to {@link #cardinality}. - */ - public long size() { - return capacity(); - } - - /** - * @see java.util.BitSet#length() - * @return Returns the "logical size" of this {@code BitSet}: the index of the highest set bit in - * the {@code BitSet} plus one. - */ - public long length() { - trimTrailingZeros(); - if (wlen == 0) return 0; - return (((long) wlen - 1) << 6) + (64 - Long.numberOfLeadingZeros(bits[wlen - 1])); - } - - /** - * @return Returns true if there are no set bits - */ - public boolean isEmpty() { - return cardinality() == 0; - } - - /** - * @param index The index. - * @return Returns true or false for the specified bit index. - */ - public boolean get(int index) { - int i = index >> 6; // div 64 - // signed shift will keep a negative index and force an - // array-index-out-of-bounds-exception, removing the need for an explicit check. - if (i >= bits.length) return false; - - int bit = index & 0x3f; // mod 64 - long bitmask = 1L << bit; - return (bits[i] & bitmask) != 0; - } - - /** - * @param index The index. - * @return Returns true or false for the specified bit index. - */ - public boolean get(long index) { - int i = (int) (index >> 6); // div 64 - if (i >= bits.length) return false; - int bit = (int) index & 0x3f; // mod 64 - long bitmask = 1L << bit; - return (bits[i] & bitmask) != 0; - } - - /** - * Sets a bit, expanding the set size if necessary. - * - * @param index the index to set - */ - public void set(long index) { - int wordNum = expandingWordNum(index); - int bit = (int) index & 0x3f; - long bitmask = 1L << bit; - bits[wordNum] |= bitmask; - } - - /** - * Sets a range of bits, expanding the set size if necessary - * - * @param startIndex lower index - * @param endIndex one-past the last bit to set - */ - public void set(long startIndex, long endIndex) { - if (endIndex <= startIndex) return; - - int startWord = (int) (startIndex >> 6); - - // since endIndex is one past the end, this is index of the last - // word to be changed. - int endWord = expandingWordNum(endIndex - 1); - - long startmask = -1L << startIndex; - long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex - // due to wrap - - if (startWord == endWord) { - bits[startWord] |= (startmask & endmask); - return; - } - - bits[startWord] |= startmask; - Arrays.fill(bits, startWord + 1, endWord, -1L); - bits[endWord] |= endmask; - } - - protected int expandingWordNum(long index) { - int wordNum = (int) (index >> 6); - if (wordNum >= wlen) { - ensureCapacity(index + 1); - wlen = wordNum + 1; - } - return wordNum; - } - - /** Clears all bits. */ - public void clear() { - Arrays.fill(bits, 0); - this.wlen = 0; - } - - /** - * clears a bit, allowing access beyond the current set size without changing the size. - * - * @param index the index to clear - */ - public void clear(long index) { - int wordNum = (int) (index >> 6); // div 64 - if (wordNum >= wlen) return; - int bit = (int) index & 0x3f; // mod 64 - long bitmask = 1L << bit; - bits[wordNum] &= ~bitmask; - } - - /** - * Clears a range of bits. Clearing past the end does not change the size of the set. - * - * @param startIndex lower index - * @param endIndex one-past the last bit to clear - */ - public void clear(int startIndex, int endIndex) { - if (endIndex <= startIndex) return; - - int startWord = (startIndex >> 6); - if (startWord >= wlen) return; - - // since endIndex is one past the end, this is index of the last - // word to be changed. - int endWord = ((endIndex - 1) >> 6); - - long startmask = -1L << startIndex; - long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex - // due to wrap - - // invert masks since we are clearing - startmask = ~startmask; - endmask = ~endmask; - - if (startWord == endWord) { - bits[startWord] &= (startmask | endmask); - return; - } - - bits[startWord] &= startmask; - - int middle = Math.min(wlen, endWord); - Arrays.fill(bits, startWord + 1, middle, 0L); - if (endWord < wlen) { - bits[endWord] &= endmask; - } - } - - /** - * Clears a range of bits. Clearing past the end does not change the size of the set. - * - * @param startIndex lower index - * @param endIndex one-past the last bit to clear - */ - public void clear(long startIndex, long endIndex) { - if (endIndex <= startIndex) return; - - int startWord = (int) (startIndex >> 6); - if (startWord >= wlen) return; - - // since endIndex is one past the end, this is index of the last - // word to be changed. - int endWord = (int) ((endIndex - 1) >> 6); - - long startmask = -1L << startIndex; - long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex - // due to wrap - - // invert masks since we are clearing - startmask = ~startmask; - endmask = ~endmask; - - if (startWord == endWord) { - bits[startWord] &= (startmask | endmask); - return; - } - - bits[startWord] &= startmask; - - int middle = Math.min(wlen, endWord); - Arrays.fill(bits, startWord + 1, middle, 0L); - if (endWord < wlen) { - bits[endWord] &= endmask; - } - } - - /** - * Sets a bit and returns the previous value. The index should be less than the BitSet size. - * - * @param index the index to set - * @return previous state of the index - */ - public boolean getAndSet(int index) { - int wordNum = index >> 6; // div 64 - int bit = index & 0x3f; // mod 64 - long bitmask = 1L << bit; - boolean val = (bits[wordNum] & bitmask) != 0; - bits[wordNum] |= bitmask; - return val; - } - - /** - * Sets a bit and returns the previous value. The index should be less than the BitSet size. - * - * @param index the index to set - * @return previous state of the index - */ - public boolean getAndSet(long index) { - int wordNum = (int) (index >> 6); // div 64 - int bit = (int) index & 0x3f; // mod 64 - long bitmask = 1L << bit; - boolean val = (bits[wordNum] & bitmask) != 0; - bits[wordNum] |= bitmask; - return val; - } - - /** - * Flips a bit, expanding the set size if necessary. - * - * @param index the index to flip - */ - public void flip(long index) { - int wordNum = expandingWordNum(index); - int bit = (int) index & 0x3f; // mod 64 - long bitmask = 1L << bit; - bits[wordNum] ^= bitmask; - } - - /** - * flips a bit and returns the resulting bit value. The index should be less than the BitSet size. - * - * @param index the index to flip - * @return previous state of the index - */ - public boolean flipAndGet(int index) { - int wordNum = index >> 6; // div 64 - int bit = index & 0x3f; // mod 64 - long bitmask = 1L << bit; - bits[wordNum] ^= bitmask; - return (bits[wordNum] & bitmask) != 0; - } - - /** - * flips a bit and returns the resulting bit value. The index should be less than the BitSet size. - * - * @param index the index to flip - * @return previous state of the index - */ - public boolean flipAndGet(long index) { - int wordNum = (int) (index >> 6); // div 64 - int bit = (int) index & 0x3f; // mod 64 - long bitmask = 1L << bit; - bits[wordNum] ^= bitmask; - return (bits[wordNum] & bitmask) != 0; - } - - /** - * Flips a range of bits, expanding the set size if necessary - * - * @param startIndex lower index - * @param endIndex one-past the last bit to flip - */ - public void flip(long startIndex, long endIndex) { - if (endIndex <= startIndex) return; - int startWord = (int) (startIndex >> 6); - - // since endIndex is one past the end, this is index of the last - // word to be changed. - int endWord = expandingWordNum(endIndex - 1); - - long startmask = -1L << startIndex; - long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex - // due to wrap - - if (startWord == endWord) { - bits[startWord] ^= (startmask & endmask); - return; - } - - bits[startWord] ^= startmask; - - for (int i = startWord + 1; i < endWord; i++) { - bits[i] = ~bits[i]; - } - - bits[endWord] ^= endmask; - } - - /** - * @return the number of set bits - */ - public long cardinality() { - return BitUtil.pop_array(bits, 0, wlen); - } - - /** - * @param a The first set - * @param b The second set - * @return Returns the popcount or cardinality of the intersection of the two sets. Neither set is - * modified. - */ - public static long intersectionCount(BitSet a, BitSet b) { - return BitUtil.pop_intersect(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); - } - - /** - * @param a The first set - * @param b The second set - * @return Returns the popcount or cardinality of the union of the two sets. Neither set is - * modified. - */ - public static long unionCount(BitSet a, BitSet b) { - long tot = BitUtil.pop_union(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); - if (a.wlen < b.wlen) { - tot += BitUtil.pop_array(b.bits, a.wlen, b.wlen - a.wlen); - } else if (a.wlen > b.wlen) { - tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen - b.wlen); - } - return tot; - } - - /** - * @param a The first set - * @param b The second set - * @return Returns the popcount or cardinality of "a and not b" or "intersection(a, not(b))". - * Neither set is modified. - */ - public static long andNotCount(BitSet a, BitSet b) { - long tot = BitUtil.pop_andnot(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); - if (a.wlen > b.wlen) { - tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen - b.wlen); - } - return tot; - } - - /** - * @param a The first set - * @param b The second set - * @return Returns the popcount or cardinality of the exclusive-or of the two sets. Neither set is - * modified. - */ - public static long xorCount(BitSet a, BitSet b) { - long tot = BitUtil.pop_xor(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); - if (a.wlen < b.wlen) { - tot += BitUtil.pop_array(b.bits, a.wlen, b.wlen - a.wlen); - } else if (a.wlen > b.wlen) { - tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen - b.wlen); - } - return tot; - } - - /** - * @param index The index to start scanning from, inclusive. - * @return Returns the index of the first set bit starting at the index specified. -1 is returned - * if there are no more set bits. - */ - public int nextSetBit(int index) { - int i = index >> 6; - if (i >= wlen) return -1; - int subIndex = index & 0x3f; // index within the word - long word = bits[i] >> subIndex; // skip all the bits to the right of index - - if (word != 0) { - return (i << 6) + subIndex + Long.numberOfTrailingZeros(word); - } - - while (++i < wlen) { - word = bits[i]; - if (word != 0) return (i << 6) + Long.numberOfTrailingZeros(word); - } - - return -1; - } - - /** - * @param index The index to start scanning from, inclusive. - * @return Returns the index of the first set bit starting at the index specified. -1 is returned - * if there are no more set bits. - */ - public long nextSetBit(long index) { - int i = (int) (index >>> 6); - if (i >= wlen) return -1; - int subIndex = (int) index & 0x3f; // index within the word - long word = bits[i] >>> subIndex; // skip all the bits to the right of index - - if (word != 0) { - return (((long) i) << 6) + (subIndex + Long.numberOfTrailingZeros(word)); - } - - while (++i < wlen) { - word = bits[i]; - if (word != 0) return (((long) i) << 6) + Long.numberOfTrailingZeros(word); - } - - return -1; - } - - @Override - public Object clone() { - try { - BitSet obs = (BitSet) super.clone(); - obs.bits = (long[]) obs.bits.clone(); // hopefully an array clone is as - // fast(er) than arraycopy - return obs; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** - * this = this AND other - * - * @param other The bitset to intersect with. - */ - public void intersect(BitSet other) { - int newLen = Math.min(this.wlen, other.wlen); - long[] thisArr = this.bits; - long[] otherArr = other.bits; - // testing against zero can be more efficient - int pos = newLen; - while (--pos >= 0) { - thisArr[pos] &= otherArr[pos]; - } - if (this.wlen > newLen) { - // fill zeros from the new shorter length to the old length - Arrays.fill(bits, newLen, this.wlen, 0); - } - this.wlen = newLen; - } - - /** - * this = this OR other - * - * @param other The bitset to union with. - */ - public void union(BitSet other) { - int newLen = Math.max(wlen, other.wlen); - ensureCapacityWords(newLen); - - long[] thisArr = this.bits; - long[] otherArr = other.bits; - int pos = Math.min(wlen, other.wlen); - while (--pos >= 0) { - thisArr[pos] |= otherArr[pos]; - } - if (this.wlen < newLen) { - System.arraycopy(otherArr, this.wlen, thisArr, this.wlen, newLen - this.wlen); - } - this.wlen = newLen; - } - - /** - * Remove all elements set in other: this = this AND_NOT other - * - * @param other The other bitset. - */ - public void remove(BitSet other) { - int idx = Math.min(wlen, other.wlen); - long[] thisArr = this.bits; - long[] otherArr = other.bits; - while (--idx >= 0) { - thisArr[idx] &= ~otherArr[idx]; - } - } - - /** - * this = this XOR other - * - * @param other The other bitset. - */ - public void xor(BitSet other) { - int newLen = Math.max(wlen, other.wlen); - ensureCapacityWords(newLen); - - long[] thisArr = this.bits; - long[] otherArr = other.bits; - int pos = Math.min(wlen, other.wlen); - while (--pos >= 0) { - thisArr[pos] ^= otherArr[pos]; - } - if (this.wlen < newLen) { - System.arraycopy(otherArr, this.wlen, thisArr, this.wlen, newLen - this.wlen); - } - this.wlen = newLen; - } - - // some BitSet compatibility methods - - // ** see {@link intersect} */ - public void and(BitSet other) { - intersect(other); - } - - // ** see {@link union} */ - public void or(BitSet other) { - union(other); - } - - // ** see {@link andNot} */ - public void andNot(BitSet other) { - remove(other); - } - - /** - * @param other The other bitset. - * @return true if the sets have any elements in common - */ - public boolean intersects(BitSet other) { - int pos = Math.min(this.wlen, other.wlen); - long[] thisArr = this.bits; - long[] otherArr = other.bits; - while (--pos >= 0) { - if ((thisArr[pos] & otherArr[pos]) != 0) return true; - } - return false; - } - - /** - * Expand the long[] with the size given as a number of words (64 bit longs). getNumWords() is - * unchanged by this call. - * - * @param numWords The size to expand to (64-bit long words) - */ - public void ensureCapacityWords(int numWords) { - if (bits.length < numWords) { - bits = grow(bits, numWords); - } - } - - public static long[] grow(long[] array, int minSize) { - if (array.length < minSize) { - long[] newArray = new long[getNextSize(minSize)]; - System.arraycopy(array, 0, newArray, 0, array.length); - return newArray; - } else return array; - } - - public static int getNextSize(int targetSize) { - /* - * This over-allocates proportional to the list size, making room for additional - * growth. The over-allocation is mild, but is enough to give linear-time - * amortized behavior over a long sequence of appends() in the presence of a - * poorly-performing system realloc(). The growth pattern is: 0, 4, 8, 16, 25, 35, - * 46, 58, 72, 88, ... - */ - return (targetSize >> 3) + (targetSize < 9 ? 3 : 6) + targetSize; - } - - /** - * Ensure that the long[] is big enough to hold numBits, expanding it if necessary. getNumWords() - * is unchanged by this call. - * - * @param numBits The number of bits to expand to - */ - public void ensureCapacity(long numBits) { - ensureCapacityWords(bits2words(numBits)); - } - - /** Lowers {@link #wlen}, the number of words in use, by checking for trailing zero words. */ - public void trimTrailingZeros() { - int idx = wlen - 1; - while (idx >= 0 && bits[idx] == 0) idx--; - wlen = idx + 1; - } - - /* - * returns the number of 64 bit words it would take to hold numBits - */ - public static int bits2words(long numBits) { - return (int) (((numBits - 1) >>> 6) + 1); - } - - /* returns true if both sets have the same bits set */ - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof BitSet)) return false; - - BitSet a; - BitSet b = (BitSet) o; - - // make a the larger set. - if (b.wlen > this.wlen) { - a = b; - b = this; - } else { - a = this; - } - - // check for any set bits out of the range of b - for (int i = a.wlen - 1; i >= b.wlen; i--) { - if (a.bits[i] != 0) return false; - } - - for (int i = b.wlen - 1; i >= 0; i--) { - if (a.bits[i] != b.bits[i]) return false; - } - - return true; - } - - @Override - public int hashCode() { - // Start with a zero hash and use a mix that results in zero if the input is zero. - // This effectively truncates trailing zeros without an explicit check. - long h = 0; - for (int i = bits.length; --i >= 0; ) { - h ^= bits[i]; - h = (h << 1) | (h >>> 63); // rotate left - } - - // fold leftmost bits into right and add a constant to prevent - // empty sets from returning 0, which is too common. - return (int) ((h >> 32) ^ h) + 0x98761234; - } - - @Override - public String toString() { - long bit = nextSetBit(0); - if (bit < 0) { - return "{}"; - } - - final StringBuilder builder = new StringBuilder(); - builder.append("{"); - - builder.append(Long.toString(bit)); - while ((bit = nextSetBit(bit + 1)) >= 0) { - builder.append(", "); - builder.append(Long.toString(bit)); - } - builder.append("}"); - - return builder.toString(); - } - - /** - * Returns a view over this bitset data compatible with {@link IntLookupContainer}. A new object - * is always returned, but its methods reflect the current state of the bitset (the view is not a - * snapshot). - * - *

Methods of the returned {@link IntLookupContainer} may throw a {@link RuntimeException} if - * the cardinality of this bitset exceeds the int range. - * - * @return The view of this bitset as {@link IntLookupContainer}. - */ - public IntLookupContainer asIntLookupContainer() { - return new IntLookupContainer() { - @Override - public int size() { - return getCurrentCardinality(); - } - - @Override - public boolean isEmpty() { - return BitSet.this.isEmpty(); - } - - @Override - public Iterator iterator() { - return new Iterator() { - private long nextBitSet = BitSet.this.nextSetBit(0); - private final IntCursor cursor = new IntCursor(); - - @Override - public boolean hasNext() { - return nextBitSet >= 0; - } - - @Override - public IntCursor next() { - final long value = nextBitSet; - if (value < 0) throw new NoSuchElementException(); - if (value > Integer.MAX_VALUE) - throw new RuntimeException("BitSet range larger than maximum positive integer."); - - nextBitSet = BitSet.this.nextSetBit(value + 1); - cursor.index = cursor.value = (int) value; - return cursor; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - @Override - public int[] toArray() { - final int[] data = new int[getCurrentCardinality()]; - final BitSetIterator i = BitSet.this.iterator(); - for (int j = 0, bit = i.nextSetBit(); bit >= 0; bit = i.nextSetBit()) { - data[j++] = bit; - } - return data; - } - - @Override - public T forEach(T predicate) { - final BitSetIterator i = BitSet.this.iterator(); - for (int bit = i.nextSetBit(); bit >= 0; bit = i.nextSetBit()) { - if (predicate.apply(bit) == false) break; - } - - return predicate; - } - - @Override - public T forEach(T procedure) { - final BitSetIterator i = BitSet.this.iterator(); - for (int bit = i.nextSetBit(); bit >= 0; bit = i.nextSetBit()) { - procedure.apply(bit); - } - - return procedure; - } - - @Override - public boolean contains(int index) { - return index < 0 || BitSet.this.get(index); - } - - /** - * Rounds the bitset's cardinality to an integer or throws a {@link RuntimeException} if the - * cardinality exceeds maximum int range. - */ - private int getCurrentCardinality() { - long cardinality = BitSet.this.cardinality(); - if (cardinality > Integer.MAX_VALUE) - throw new RuntimeException( - "Bitset is larger than maximum positive integer: " + cardinality); - return (int) cardinality; - } - }; - } - - /** - * Returns a view over this bitset data compatible with {@link LongLookupContainer}. A new object - * is always returned, but its methods reflect the current state of the bitset (the view is not a - * snapshot). - * - * @return The view of this bitset as {@link LongLookupContainer}. - */ - public LongLookupContainer asLongLookupContainer() { - return new LongLookupContainer() { - @Override - public int size() { - return getCurrentCardinality(); - } - - @Override - public boolean isEmpty() { - return BitSet.this.isEmpty(); - } - - @Override - public Iterator iterator() { - return new Iterator() { - private long nextBitSet = BitSet.this.nextSetBit(0); - private final LongCursor cursor = new LongCursor(); - - @Override - public boolean hasNext() { - return nextBitSet >= 0; - } - - @Override - public LongCursor next() { - final long value = nextBitSet; - if (value < 0) throw new NoSuchElementException(); - - nextBitSet = BitSet.this.nextSetBit(value + 1); - cursor.index = (int) value; - cursor.value = value; - return cursor; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - @Override - public long[] toArray() { - final long[] data = new long[getCurrentCardinality()]; - final BitSet bset = BitSet.this; - int j = 0; - for (long bit = bset.nextSetBit((long) 0); bit >= 0; bit = bset.nextSetBit(bit + 1)) { - data[j++] = bit; - } - return data; - } - - @Override - public T forEach(T predicate) { - final BitSet bset = BitSet.this; - for (long bit = bset.nextSetBit((long) 0); bit >= 0; bit = bset.nextSetBit(bit + 1)) { - if (predicate.apply(bit) == false) break; - } - - return predicate; - } - - @Override - public T forEach(T procedure) { - final BitSet bset = BitSet.this; - for (long bit = bset.nextSetBit((long) 0); bit >= 0; bit = bset.nextSetBit(bit + 1)) { - procedure.apply(bit); - } - - return procedure; - } - - @Override - public boolean contains(long index) { - return index < 0 || BitSet.this.get(index); - } - - /** - * Rounds the bitset's cardinality to an integer or throws a {@link RuntimeException} if the - * cardinality exceeds maximum int range. - */ - private int getCurrentCardinality() { - long cardinality = BitSet.this.cardinality(); - if (cardinality > Integer.MAX_VALUE) - throw new RuntimeException( - "Bitset is larger than maximum positive integer: " + cardinality); - return (int) cardinality; - } - }; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/BitSetIterator.java b/sources/main/java/com/carrotsearch/hppc/BitSetIterator.java deleted file mode 100644 index 35aa3e06..00000000 --- a/sources/main/java/com/carrotsearch/hppc/BitSetIterator.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -/** - * An iterator to iterate over set bits in an BitSet. This is faster than nextSetBit() for iterating - * over the complete set of bits, especially when the density of the bits set is high. - */ -public class BitSetIterator { - // The General Idea: instead of having an array per byte that has - // the offsets of the next set bit, that array could be - // packed inside a 32 bit integer (8 4 bit numbers). That - // should be faster than accessing an array for each index, and - // the total array size is kept smaller (256*sizeof(int))=1K - static final int[] bitlist = { - 0x0, - 0x1, - 0x2, - 0x21, - 0x3, - 0x31, - 0x32, - 0x321, - 0x4, - 0x41, - 0x42, - 0x421, - 0x43, - 0x431, - 0x432, - 0x4321, - 0x5, - 0x51, - 0x52, - 0x521, - 0x53, - 0x531, - 0x532, - 0x5321, - 0x54, - 0x541, - 0x542, - 0x5421, - 0x543, - 0x5431, - 0x5432, - 0x54321, - 0x6, - 0x61, - 0x62, - 0x621, - 0x63, - 0x631, - 0x632, - 0x6321, - 0x64, - 0x641, - 0x642, - 0x6421, - 0x643, - 0x6431, - 0x6432, - 0x64321, - 0x65, - 0x651, - 0x652, - 0x6521, - 0x653, - 0x6531, - 0x6532, - 0x65321, - 0x654, - 0x6541, - 0x6542, - 0x65421, - 0x6543, - 0x65431, - 0x65432, - 0x654321, - 0x7, - 0x71, - 0x72, - 0x721, - 0x73, - 0x731, - 0x732, - 0x7321, - 0x74, - 0x741, - 0x742, - 0x7421, - 0x743, - 0x7431, - 0x7432, - 0x74321, - 0x75, - 0x751, - 0x752, - 0x7521, - 0x753, - 0x7531, - 0x7532, - 0x75321, - 0x754, - 0x7541, - 0x7542, - 0x75421, - 0x7543, - 0x75431, - 0x75432, - 0x754321, - 0x76, - 0x761, - 0x762, - 0x7621, - 0x763, - 0x7631, - 0x7632, - 0x76321, - 0x764, - 0x7641, - 0x7642, - 0x76421, - 0x7643, - 0x76431, - 0x76432, - 0x764321, - 0x765, - 0x7651, - 0x7652, - 0x76521, - 0x7653, - 0x76531, - 0x76532, - 0x765321, - 0x7654, - 0x76541, - 0x76542, - 0x765421, - 0x76543, - 0x765431, - 0x765432, - 0x7654321, - 0x8, - 0x81, - 0x82, - 0x821, - 0x83, - 0x831, - 0x832, - 0x8321, - 0x84, - 0x841, - 0x842, - 0x8421, - 0x843, - 0x8431, - 0x8432, - 0x84321, - 0x85, - 0x851, - 0x852, - 0x8521, - 0x853, - 0x8531, - 0x8532, - 0x85321, - 0x854, - 0x8541, - 0x8542, - 0x85421, - 0x8543, - 0x85431, - 0x85432, - 0x854321, - 0x86, - 0x861, - 0x862, - 0x8621, - 0x863, - 0x8631, - 0x8632, - 0x86321, - 0x864, - 0x8641, - 0x8642, - 0x86421, - 0x8643, - 0x86431, - 0x86432, - 0x864321, - 0x865, - 0x8651, - 0x8652, - 0x86521, - 0x8653, - 0x86531, - 0x86532, - 0x865321, - 0x8654, - 0x86541, - 0x86542, - 0x865421, - 0x86543, - 0x865431, - 0x865432, - 0x8654321, - 0x87, - 0x871, - 0x872, - 0x8721, - 0x873, - 0x8731, - 0x8732, - 0x87321, - 0x874, - 0x8741, - 0x8742, - 0x87421, - 0x8743, - 0x87431, - 0x87432, - 0x874321, - 0x875, - 0x8751, - 0x8752, - 0x87521, - 0x8753, - 0x87531, - 0x87532, - 0x875321, - 0x8754, - 0x87541, - 0x87542, - 0x875421, - 0x87543, - 0x875431, - 0x875432, - 0x8754321, - 0x876, - 0x8761, - 0x8762, - 0x87621, - 0x8763, - 0x87631, - 0x87632, - 0x876321, - 0x8764, - 0x87641, - 0x87642, - 0x876421, - 0x87643, - 0x876431, - 0x876432, - 0x8764321, - 0x8765, - 0x87651, - 0x87652, - 0x876521, - 0x87653, - 0x876531, - 0x876532, - 0x8765321, - 0x87654, - 0x876541, - 0x876542, - 0x8765421, - 0x876543, - 0x8765431, - 0x8765432, - 0x87654321 - }; - - /** - * *** the python code that generated bitlist def bits2int(val): arr=0 for shift in range(8,0,-1): - * if val & 0x80: arr = (arr << 4) | shift val = val << 1 return arr - * - *

def int_table(): tbl = [ hex(bits2int(val)).strip('L') for val in range(256) ] return - * ','.join(tbl) **** - */ - - // hmmm, what about an iterator that finds zeros though, - // or a reverse iterator... should they be separate classes - // for efficiency, or have a common root interface? (or - // maybe both? could ask for a SetBitsIterator, etc... - - private final long[] arr; - - private final int words; - private int i = -1; - private long word; - private int wordShift; - private int indexArray; - - public BitSetIterator(BitSet obs) { - this(obs.bits, obs.wlen); - } - - public BitSetIterator(long[] bits, int numWords) { - arr = bits; - words = numWords; - } - - // 64 bit shifts - private void shift() { - if ((int) word == 0) { - wordShift += 32; - word = word >>> 32; - } - if ((word & 0x0000FFFF) == 0) { - wordShift += 16; - word >>>= 16; - } - if ((word & 0x000000FF) == 0) { - wordShift += 8; - word >>>= 8; - } - indexArray = bitlist[(int) word & 0xff]; - } - - public static final int NO_MORE = -1; - - public int nextSetBit() { - if (indexArray == 0) { - if (word != 0) { - word >>>= 8; - wordShift += 8; - } - - while (word == 0) { - if (++i >= words) { - return NO_MORE; - } - word = arr[i]; - wordShift = -1; // loop invariant code motion should move this - } - - // after the first time, should I go with a linear search, or - // stick with the binary search in shift? - shift(); - } - - int bitIndex = (indexArray & 0x0f) + wordShift; - indexArray >>>= 4; - // should i<<6 be cached as a separate variable? - // it would only save one cycle in the best circumstances. - return (i << 6) + bitIndex; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/BitUtil.java b/sources/main/java/com/carrotsearch/hppc/BitUtil.java deleted file mode 100644 index 61a628d5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/BitUtil.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -/** A variety of high efficiency bit twiddling routines. */ -final class BitUtil { - private BitUtil() {} // no instance - - // The pop methods used to rely on bit-manipulation tricks for speed but it - // turns out that it is faster to use the Long.bitCount method (which is an - // intrinsic since Java 6u18) in a naive loop, see LUCENE-2221 - - /** Returns the number of set bits in an array of longs. */ - public static long pop_array(long[] arr, int wordOffset, int numWords) { - long popCount = 0; - for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { - popCount += Long.bitCount(arr[i]); - } - return popCount; - } - - /** - * Returns the popcount or cardinality of the two sets after an intersection. Neither array is - * modified. - */ - public static long pop_intersect(long[] arr1, long[] arr2, int wordOffset, int numWords) { - long popCount = 0; - for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { - popCount += Long.bitCount(arr1[i] & arr2[i]); - } - return popCount; - } - - /** Returns the popcount or cardinality of the union of two sets. Neither array is modified. */ - public static long pop_union(long[] arr1, long[] arr2, int wordOffset, int numWords) { - long popCount = 0; - for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { - popCount += Long.bitCount(arr1[i] | arr2[i]); - } - return popCount; - } - - /** Returns the popcount or cardinality of A & ~B. Neither array is modified. */ - public static long pop_andnot(long[] arr1, long[] arr2, int wordOffset, int numWords) { - long popCount = 0; - for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { - popCount += Long.bitCount(arr1[i] & ~arr2[i]); - } - return popCount; - } - - /** Returns the popcount or cardinality of A ^ B Neither array is modified. */ - public static long pop_xor(long[] arr1, long[] arr2, int wordOffset, int numWords) { - long popCount = 0; - for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { - popCount += Long.bitCount(arr1[i] ^ arr2[i]); - } - return popCount; - } - - /** - * returns the next highest power of two, or the current value if it's already a power of two or - * zero - */ - public static int nextHighestPowerOfTwo(int v) { - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; - } - - /** - * returns the next highest power of two, or the current value if it's already a power of two or - * zero - */ - public static long nextHighestPowerOfTwo(long v) { - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v |= v >> 32; - v++; - return v; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/BoundedProportionalArraySizingStrategy.java b/sources/main/java/com/carrotsearch/hppc/BoundedProportionalArraySizingStrategy.java deleted file mode 100644 index 14c5a9ab..00000000 --- a/sources/main/java/com/carrotsearch/hppc/BoundedProportionalArraySizingStrategy.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import java.util.ArrayList; - -/** - * Array resizing proportional to the current buffer size, optionally kept within the given minimum - * and maximum growth limits. Java's {@link ArrayList} uses: - * - *

- * minGrow = 1
- * maxGrow = Integer.MAX_VALUE (unbounded)
- * growRatio = 1.5f
- * 
- */ -public final class BoundedProportionalArraySizingStrategy implements ArraySizingStrategy { - - /** Instance of {@link BoundedProportionalArraySizingStrategy} with default values. */ - public static final BoundedProportionalArraySizingStrategy DEFAULT_INSTANCE = - new BoundedProportionalArraySizingStrategy(); - - /** - * Maximum allocable array length (approximately the largest positive integer decreased by the - * array's object header). - */ - public static final int MAX_ARRAY_LENGTH = - Integer.MAX_VALUE - /* aligned array header + slack */ 32; - - /** Minimum grow count. */ - public static final int DEFAULT_MIN_GROW_COUNT = 10; - - /** Maximum grow count (unbounded). */ - public static final int DEFAULT_MAX_GROW_COUNT = MAX_ARRAY_LENGTH; - - /** Default resize is by half the current buffer's size. */ - public static final float DEFAULT_GROW_RATIO = 1.5f; - - /** Minimum number of elements to grow, if limit exceeded. */ - public final int minGrowCount; - - /** Maximum number of elements to grow, if limit exceeded. */ - public final int maxGrowCount; - - /** - * The current buffer length is multiplied by this ratio to get the first estimate for the new - * size. To double the size of the current buffer, for example, set to 2. - */ - public final float growRatio; - - /** Create the default sizing strategy. */ - public BoundedProportionalArraySizingStrategy() { - this(DEFAULT_MIN_GROW_COUNT, DEFAULT_MAX_GROW_COUNT, DEFAULT_GROW_RATIO); - } - - /** - * Create the sizing strategy with custom policies. - * - * @param minGrow Minimum number of elements to grow by when expanding. - * @param maxGrow Maximum number of elements to grow by when expanding. - * @param ratio The ratio of expansion compared to the previous buffer size. - */ - public BoundedProportionalArraySizingStrategy(int minGrow, int maxGrow, float ratio) { - assert minGrow >= 1 : "Min grow must be >= 1."; - assert maxGrow >= minGrow : "Max grow must be >= min grow."; - assert ratio >= 1f : "Growth ratio must be >= 1 (was " + ratio + ")."; - - this.minGrowCount = minGrow; - this.maxGrowCount = maxGrow; - this.growRatio = ratio - 1.0f; - } - - /** - * Grow according to {@link #growRatio}, {@link #minGrowCount} and {@link #maxGrowCount}. - * - * @param currentBufferLength The current length of the buffer. - * @param elementsCount The number of elements stored in the buffer. - * @param expectedAdditions The number of expected additions to the buffer. - * @return New buffer size. - */ - public int grow(int currentBufferLength, int elementsCount, int expectedAdditions) { - long growBy = (long) ((long) currentBufferLength * growRatio); - growBy = Math.max(growBy, minGrowCount); - growBy = Math.min(growBy, maxGrowCount); - long growTo = Math.min(MAX_ARRAY_LENGTH, growBy + currentBufferLength); - long newSize = Math.max((long) elementsCount + expectedAdditions, growTo); - - if (newSize > MAX_ARRAY_LENGTH) { - throw new BufferAllocationException( - "Java array size exceeded (current length: %d, elements: %d, expected additions: %d)", - currentBufferLength, elementsCount, expectedAdditions); - } - - return (int) newSize; - } - - @Override - public long ramBytesAllocated() { - // int: minGrowCount, maxGrowCount - // float: growRatio - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + Integer.BYTES * 2 + Float.BYTES; - } - - @Override - public long ramBytesUsed() { - return ramBytesAllocated(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/BufferAllocationException.java b/sources/main/java/com/carrotsearch/hppc/BufferAllocationException.java deleted file mode 100644 index f09ef3c8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/BufferAllocationException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import java.util.IllegalFormatException; -import java.util.Locale; - -public class BufferAllocationException extends RuntimeException { - public BufferAllocationException(String message) { - super(message); - } - - public BufferAllocationException(String message, Object... args) { - this(message, null, args); - } - - public BufferAllocationException(String message, Throwable t, Object... args) { - super(formatMessage(message, t, args), t); - } - - private static String formatMessage(String message, Throwable t, Object... args) { - try { - return String.format(Locale.ROOT, message, args); - } catch (IllegalFormatException e) { - BufferAllocationException substitute = - new BufferAllocationException(message + " [ILLEGAL FORMAT, ARGS SUPPRESSED]"); - if (t != null) { - substitute.addSuppressed(t); - } - substitute.addSuppressed(e); - throw substitute; - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ByteArrayDeque.java b/sources/main/java/com/carrotsearch/hppc/ByteArrayDeque.java deleted file mode 100644 index b9c809c1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ByteArrayDeque.java +++ /dev/null @@ -1,776 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.ByteCursor; -import com.carrotsearch.hppc.predicates.BytePredicate; -import com.carrotsearch.hppc.procedures.ByteProcedure; -import java.util.*; - -/** An array-backed {@link ByteDeque}. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") -public class ByteArrayDeque extends AbstractByteCollection - implements ByteDeque, Preallocable, Cloneable, Accountable { - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** Internal array for storing elements of the deque. */ - public byte[] buffer = ByteArrayList.EMPTY_ARRAY; - - /** - * The index of the element at the head of the deque or an arbitrary number equal to tail if the - * deque is empty. - */ - public int head; - - /** The index at which the next element would be added to the tail of the deque. */ - public int tail; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public ByteArrayDeque() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ByteArrayDeque(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public ByteArrayDeque(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - ensureCapacity(expectedElements); - } - - /** - * Creates a new deque from elements of another container, appending elements at the end of the - * deque in the iteration order. - */ - public ByteArrayDeque(ByteContainer container) { - this(container.size()); - addLast(container); - } - - /** {@inheritDoc} */ - @Override - public void addFirst(byte e1) { - int h = oneLeft(head, buffer.length); - if (h == tail) { - ensureBufferSpace(1); - h = oneLeft(head, buffer.length); - } - buffer[head = h] = e1; - } - - /** - * Vararg-signature method for adding elements at the front of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to add. - */ - public final void addFirst(byte... elements) { - ensureBufferSpace(elements.length); - for (byte k : elements) { - addFirst(k); - } - } - - /** - * Inserts all elements from the given container to the front of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(ByteContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (ByteCursor cursor : container) { - addFirst(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the front of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(Iterable iterable) { - int size = 0; - for (ByteCursor cursor : iterable) { - addFirst(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void addLast(byte e1) { - int t = oneRight(tail, buffer.length); - if (head == t) { - ensureBufferSpace(1); - t = oneRight(tail, buffer.length); - } - buffer[tail] = e1; - tail = t; - } - - /** - * Vararg-signature method for adding elements at the end of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to iterate over. - */ - public final void addLast(byte... elements) { - ensureBufferSpace(1); - for (byte k : elements) { - addLast(k); - } - } - - /** - * Inserts all elements from the given container to the end of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(ByteContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (ByteCursor cursor : container) { - addLast(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the end of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(Iterable iterable) { - int size = 0; - for (ByteCursor cursor : iterable) { - addLast(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public byte removeFirst() { - assert size() > 0 : "The deque is empty."; - - final byte result = buffer[head]; - buffer[head] = ((byte) 0); - head = oneRight(head, buffer.length); - return result; - } - - /** {@inheritDoc} */ - @Override - public byte removeLast() { - assert size() > 0 : "The deque is empty."; - - tail = oneLeft(tail, buffer.length); - final byte result = buffer[tail]; - buffer[tail] = ((byte) 0); - return result; - } - - /** {@inheritDoc} */ - @Override - public byte getFirst() { - assert size() > 0 : "The deque is empty."; - - return buffer[head]; - } - - /** {@inheritDoc} */ - @Override - public byte getLast() { - assert size() > 0 : "The deque is empty."; - - return buffer[oneLeft(tail, buffer.length)]; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(byte e1) { - final int index = bufferIndexOf(e1); - if (index >= 0) removeAtBufferIndex(index); - return index; - } - - /** - * Return the index of the first (counting from head) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int bufferIndexOf(byte e1) { - final int last = tail; - final int bufLen = buffer.length; - for (int i = head; i != last; i = oneRight(i, bufLen)) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(byte e1) { - final int index = lastBufferIndexOf(e1); - if (index >= 0) { - removeAtBufferIndex(index); - } - return index; - } - - /** - * Return the index of the last (counting from tail) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int lastBufferIndexOf(byte e1) { - final int bufLen = buffer.length; - final int last = oneLeft(head, bufLen); - for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { - if (((e1) == (buffer[i]))) return i; - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(byte e1) { - int removed = 0; - final int last = tail; - final int bufLen = buffer.length; - int from, to; - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (((e1) == (buffer[from]))) { - buffer[from] = ((byte) 0); - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((byte) 0); - } - - to = oneRight(to, bufLen); - } - - tail = to; - return removed; - } - - /** - * Removes the element at index in the internal {#link {@link #buffer} array, - * returning its value. - * - * @param index Index of the element to remove. The index must be located between {@link #head} - * and {@link #tail} in modulo {@link #buffer} arithmetic. - */ - public void removeAtBufferIndex(int index) { - assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) - : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; - - // Cache fields in locals (hopefully moved to registers). - final byte[] buffer = this.buffer; - final int bufLen = buffer.length; - final int lastIndex = bufLen - 1; - final int head = this.head; - final int tail = this.tail; - - final int leftChunk = Math.abs(index - head) % bufLen; - final int rightChunk = Math.abs(tail - index) % bufLen; - - if (leftChunk < rightChunk) { - if (index >= head) { - System.arraycopy(buffer, head, buffer, head + 1, leftChunk); - } else { - System.arraycopy(buffer, 0, buffer, 1, index); - buffer[0] = buffer[lastIndex]; - System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); - } - buffer[head] = ((byte) 0); - this.head = oneRight(head, bufLen); - } else { - if (index < tail) { - System.arraycopy(buffer, index + 1, buffer, index, rightChunk); - } else { - System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); - buffer[lastIndex] = buffer[0]; - System.arraycopy(buffer, 1, buffer, 0, tail); - } - buffer[tail] = ((byte) 0); - this.tail = oneLeft(tail, bufLen); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int size() { - if (head <= tail) return tail - head; - else return (tail - head + buffer.length); - } - - /** - * {@inheritDoc} - * - *

The internal array buffers are not released as a result of this call. - * - * @see #release() - */ - @Override - public void clear() { - if (head < tail) { - Arrays.fill(buffer, head, tail, ((byte) 0)); - } else { - Arrays.fill(buffer, 0, tail, ((byte) 0)); - Arrays.fill(buffer, head, buffer.length, ((byte) 0)); - } - this.head = tail = 0; - } - - /** Release internal buffers of this deque and reallocate with the default buffer. */ - public void release() { - this.head = tail = 0; - buffer = ByteArrayList.EMPTY_ARRAY; - ensureBufferSpace(0); - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - ensureBufferSpace(expectedElements - size()); - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = buffer.length; - final int elementsCount = size(); - - if (elementsCount + expectedAdditions >= bufferLen) { - final int emptySlot = 1; // deque invariant: always an empty slot. - final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); - assert newSize >= (elementsCount + expectedAdditions + emptySlot) - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - try { - final byte[] newBuffer = (new byte[newSize]); - if (bufferLen > 0) { - toArray(newBuffer); - tail = elementsCount; - head = 0; - } - this.buffer = newBuffer; - } catch (OutOfMemoryError e) { - throw new BufferAllocationException( - "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); - } - } - } - - /** {@inheritDoc} */ - @Override - public byte[] toArray() { - - final int size = size(); - return toArray((new byte[size])); - } - - /** - * Copies elements of this deque to an array. The content of the target array is - * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). - * - * @param target The target array must be large enough to hold all elements. - * @return Returns the target argument for chaining. - */ - public byte[] toArray(byte[] target) { - assert target.length >= size() : "Target array must be >= " + size(); - - if (head < tail) { - // The contents is not wrapped around. Just copy. - System.arraycopy(buffer, head, target, 0, size()); - } else if (head > tail) { - // The contents is split. Merge elements from the following indexes: - // [head...buffer.length - 1][0, tail - 1] - final int rightCount = buffer.length - head; - System.arraycopy(buffer, head, target, 0, rightCount); - System.arraycopy(buffer, 0, target, rightCount, tail); - } - - return target; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public ByteArrayDeque clone() { - try { - - ByteArrayDeque cloned = (ByteArrayDeque) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Move one index to the left, wrapping around buffer. */ - protected static int oneLeft(int index, int modulus) { - if (index >= 1) { - return index - 1; - } - return modulus - 1; - } - - /** Move one index to the right, wrapping around buffer. */ - protected static int oneRight(int index, int modulus) { - if (index + 1 == modulus) { - return 0; - } - return index + 1; - } - - @Override - public long ramBytesAllocated() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); - } - - /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ - private final class ValueIterator extends AbstractIterator { - private final ByteCursor cursor; - private int remaining; - - public ValueIterator() { - cursor = new ByteCursor(); - cursor.index = oneLeft(head, buffer.length); - this.remaining = size(); - } - - @Override - protected ByteCursor fetch() { - if (remaining == 0) { - return done(); - } - - remaining--; - cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; - return cursor; - } - } - - /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ - private final class DescendingValueIterator extends AbstractIterator { - private final ByteCursor cursor; - private int remaining; - - public DescendingValueIterator() { - cursor = new ByteCursor(); - cursor.index = tail; - this.remaining = size(); - } - - @Override - protected ByteCursor fetch() { - if (remaining == 0) return done(); - - remaining--; - cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; - return cursor; - } - } - - /** - * Returns a cursor over the values of this deque (in head to tail order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *

-   * for (IntValueCursor c : intDeque) {
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator() { - return new ValueIterator(); - } - - /** - * Returns a cursor over the values of this deque (in tail to head order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *
-   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
-   *   final IntCursor c = i.next();
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator descendingIterator() { - return new DescendingValueIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - forEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, fromIndex, inclusive, to - * toIndex, exclusive. - */ - private void forEach(ByteProcedure procedure, int fromIndex, final int toIndex) { - final byte[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - procedure.apply(buffer[i]); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - int fromIndex = head; - int toIndex = tail; - - final byte[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (!predicate.apply(buffer[i])) { - break; - } - } - - return predicate; - } - - /** Applies procedure to all elements of this deque, tail to head. */ - @Override - public T descendingForEach(T procedure) { - descendingForEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive. - */ - private void descendingForEach(ByteProcedure procedure, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final byte[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - procedure.apply(buffer[i]); - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public T descendingForEach(T predicate) { - descendingForEach(predicate, head, tail); - return predicate; - } - - /** - * Applies predicate to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive or until the predicate returns false. - */ - private void descendingForEach(BytePredicate predicate, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final byte[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - if (!predicate.apply(buffer[i])) { - break; - } - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(BytePredicate predicate) { - final byte[] buffer = this.buffer; - final int last = tail; - final int bufLen = buffer.length; - int removed = 0; - int from, to; - from = to = head; - try { - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (predicate.apply(buffer[from])) { - buffer[from] = ((byte) 0); - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((byte) 0); - } - - to = oneRight(to, bufLen); - } - } finally { - // Keep the deque in consistent state even if the predicate throws an exception. - for (; from != last; from = oneRight(from, bufLen)) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((byte) 0); - } - - to = oneRight(to, bufLen); - } - tail = to; - } - - return removed; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(byte e) { - int fromIndex = head; - int toIndex = tail; - - final byte[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (((e) == (buffer[i]))) { - return true; - } - } - - return false; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1; - int fromIndex = head; - int toIndex = tail; - - final byte[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare order-aligned elements against another {@link ByteDeque}. */ - protected boolean equalElements(ByteArrayDeque other) { - int max = size(); - if (other.size() != max) { - return false; - } - - Iterator i1 = this.iterator(); - Iterator i2 = other.iterator(); - - while (i1.hasNext() && i2.hasNext()) { - if (!((i1.next().value) == (i2.next().value))) { - return false; - } - } - - return !i1.hasNext() && !i2.hasNext(); - } - - /** Create a new deque by pushing a variable number of arguments to the end of it. */ - public static ByteArrayDeque from(byte... elements) { - final ByteArrayDeque coll = new ByteArrayDeque(elements.length); - coll.addLast(elements); - return coll; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ByteArrayList.java b/sources/main/java/com/carrotsearch/hppc/ByteArrayList.java deleted file mode 100644 index 836c6b9d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ByteArrayList.java +++ /dev/null @@ -1,579 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.BytePredicate; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** An array-backed list of bytes. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") -public class ByteArrayList extends AbstractByteCollection - implements ByteIndexedContainer, Preallocable, Cloneable, Accountable { - /** An immutable empty buffer (array). */ - public static final byte[] EMPTY_ARRAY = new byte[0]; - - ; - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** - * Internal array for storing the list. The array may be larger than the current size ({@link - * #size()}). - */ - public byte[] buffer = EMPTY_ARRAY; - - /** Current number of elements stored in {@link #buffer}. */ - public int elementsCount; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public ByteArrayList() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ByteArrayList(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public ByteArrayList(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - buffer = Arrays.copyOf(buffer, expectedElements); - } - - /** Creates a new list from the elements of another container in its iteration order. */ - public ByteArrayList(ByteContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public void add(byte e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** - * Appends two elements at the end of the list. To add more than two elements, use add - * (vararg-version) or access the buffer directly (tight loop). - */ - public void add(byte e1, byte e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Add all elements from a range of given array to the list. */ - public void add(byte[] elements, int start, int length) { - assert length >= 0 : "Length must be >= 0"; - - ensureBufferSpace(length); - System.arraycopy(elements, start, buffer, elementsCount, length); - elementsCount += length; - } - - /** - * Vararg-signature method for adding elements at the end of the list. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void add(byte... elements) { - add(elements, 0, elements.length); - } - - /** Adds all elements from another container. */ - public int addAll(ByteContainer container) { - final int size = container.size(); - ensureBufferSpace(size); - - for (ByteCursor cursor : container) { - add(cursor.value); - } - - return size; - } - - /** Adds all elements from another iterable. */ - public int addAll(Iterable iterable) { - int size = 0; - for (ByteCursor cursor : iterable) { - add(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void insert(int index, byte e1) { - assert (index >= 0 && index <= size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; - - ensureBufferSpace(1); - System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); - buffer[index] = e1; - elementsCount++; - } - - /** {@inheritDoc} */ - @Override - public byte get(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - return buffer[index]; - } - - /** {@inheritDoc} */ - @Override - public byte set(int index, byte e1) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final byte v = buffer[index]; - buffer[index] = e1; - return v; - } - - /** {@inheritDoc} */ - @Override - public byte removeAt(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final byte v = buffer[index]; - System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); - - return v; - } - - /** {@inheritDoc} */ - @Override - public byte removeLast() { - assert elementsCount > 0; - - final byte v = buffer[--elementsCount]; - - return v; - } - - /** {@inheritDoc} */ - @Override - public void removeRange(int fromIndex, int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); - final int count = toIndex - fromIndex; - elementsCount -= count; - } - - /** {@inheritDoc} */ - @Override - public boolean removeElement(byte e1) { - return removeFirst(e1) != -1; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(byte e1) { - final int index = indexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(byte e1) { - final int index = lastIndexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(byte e1) { - int to = 0; - for (int from = 0; from < elementsCount; from++) { - if (((e1) == (buffer[from]))) { - continue; - } - if (to != from) { - buffer[to] = buffer[from]; - } - to++; - } - final int deleted = elementsCount - to; - this.elementsCount = to; - - return deleted; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(byte e1) { - return indexOf(e1) >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexOf(byte e1) { - for (int i = 0; i < elementsCount; i++) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int lastIndexOf(byte e1) { - for (int i = elementsCount - 1; i >= 0; i--) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return elementsCount == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (expectedElements > bufferLen) { - ensureBufferSpace(expectedElements - size()); - } - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (elementsCount + expectedAdditions > bufferLen) { - final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); - assert newSize >= elementsCount + expectedAdditions - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - this.buffer = Arrays.copyOf(buffer, newSize); - } - } - - /** - * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be - * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated - * values will be reset to the default value (zero). If the list is expanded, the elements beyond - * the current size are initialized with JVM-defaults (zero or null values). - */ - public void resize(int newSize) { - if (newSize <= buffer.length) { - if (newSize < elementsCount) { - Arrays.fill(buffer, newSize, elementsCount, ((byte) 0)); - } else { - Arrays.fill(buffer, elementsCount, newSize, ((byte) 0)); - } - } else { - ensureCapacity(newSize); - } - this.elementsCount = newSize; - } - - /** {@inheritDoc} */ - @Override - public int size() { - return elementsCount; - } - - /** Trim the internal buffer to the current size. */ - public void trimToSize() { - if (size() != this.buffer.length) { - this.buffer = toArray(); - } - } - - /** - * Sets the number of stored elements to zero. Releases and initializes the internal storage array - * to default values. To clear the list without cleaning the buffer, simply set the {@link - * #elementsCount} field to zero. - */ - @Override - public void clear() { - Arrays.fill(buffer, 0, elementsCount, ((byte) 0)); - this.elementsCount = 0; - } - - /** Sets the number of stored elements to zero and releases the internal storage array. */ - @Override - public void release() { - this.buffer = EMPTY_ARRAY; - this.elementsCount = 0; - } - - /** - * {@inheritDoc} - * - *

The returned array is sized to match exactly the number of elements of the stack. - */ - @Override - public byte[] toArray() { - - return Arrays.copyOf(buffer, elementsCount); - } - - /** {@inheritDoc} */ - @Override - public ByteIndexedContainer sort() { - Arrays.sort(buffer, 0, elementsCount); - return this; - } - - /** {@inheritDoc} */ - @Override - public ByteIndexedContainer reverse() { - for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { - byte tmp = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = tmp; - } - return this; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public ByteArrayList clone() { - try { - - final ByteArrayList cloned = (ByteArrayList) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1, max = elementsCount; - for (int i = 0; i < max; i++) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare index-aligned elements against another {@link ByteIndexedContainer}. */ - protected boolean equalElements(ByteArrayList other) { - int max = size(); - if (other.size() != max) { - return false; - } - - for (int i = 0; i < max; i++) { - if (!((get(i)) == (other.get(i)))) { - return false; - } - } - - return true; - } - - @Override - public long ramBytesAllocated() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); - } - - /** An iterator implementation for {@link ByteArrayList#iterator}. */ - static final class ValueIterator extends AbstractIterator { - private final ByteCursor cursor; - - private final byte[] buffer; - private final int size; - - public ValueIterator(byte[] buffer, int size) { - this.cursor = new ByteCursor(); - this.cursor.index = -1; - this.size = size; - this.buffer = buffer; - } - - @Override - protected ByteCursor fetch() { - if (cursor.index + 1 == size) return done(); - - cursor.value = buffer[++cursor.index]; - return cursor; - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new ValueIterator(buffer, size()); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - return forEach(procedure, 0, size()); - } - - /** - * Applies procedure to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive. - */ - public T forEach(T procedure, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final byte[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - procedure.apply(buffer[i]); - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(BytePredicate predicate) { - final byte[] buffer = this.buffer; - final int elementsCount = this.elementsCount; - int to = 0; - int from = 0; - try { - for (; from < elementsCount; from++) { - if (predicate.apply(buffer[from])) { - buffer[from] = ((byte) 0); - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((byte) 0); - } - to++; - } - } finally { - // Keep the list in a consistent state, even if the predicate throws an exception. - for (; from < elementsCount; from++) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((byte) 0); - } - to++; - } - - this.elementsCount = to; - } - - return elementsCount - to; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - return forEach(predicate, 0, size()); - } - - /** - * Applies predicate to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive, or until predicate returns false. - */ - public T forEach(T predicate, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final byte[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - if (!predicate.apply(buffer[i])) break; - } - - return predicate; - } - - /** - * Create a list from a variable number of arguments or an array of byte. The - * elements are copied from the argument to the internal buffer. - */ - public static ByteArrayList from(byte... elements) { - final ByteArrayList list = new ByteArrayList(elements.length); - list.add(elements); - return list; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ByteBufferVisualizer.java b/sources/main/java/com/carrotsearch/hppc/ByteBufferVisualizer.java deleted file mode 100644 index 0a39142a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ByteBufferVisualizer.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Reused buffer visualization routines. - * - * @see ByteSet#visualizeKeyDistribution(int) - * @see ByteVTypeMap#visualizeKeyDistribution(int) - */ -class ByteBufferVisualizer { - static String visualizeKeyDistribution(byte[] buffer, int max, int characters) { - final StringBuilder b = new StringBuilder(); - final char[] chars = ".123456789X".toCharArray(); - for (int i = 1, start = -1; i <= characters; i++) { - int end = (int) ((long) i * max / characters); - - if (start + 1 <= end) { - int taken = 0; - int slots = 0; - for (int slot = start + 1; slot <= end; slot++, slots++) { - if (!((buffer[slot]) == 0)) { - taken++; - } - } - b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); - start = end; - } - } - while (b.length() < characters) { - b.append(' '); - } - return b.toString(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ByteCollection.java b/sources/main/java/com/carrotsearch/hppc/ByteCollection.java deleted file mode 100644 index 2e89418e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ByteCollection.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.predicates.BytePredicate; - -/** - * A collection allows basic, efficient operations on sets of elements (difference and - * intersection). - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") -public interface ByteCollection extends ByteContainer { - /** - * Removes all occurrences of e from this collection. - * - * @param e Element to be removed from this collection, if present. - * @return The number of removed elements as a result of this call. - */ - public int removeAll(byte e); - - /** - * Removes all elements in this collection that are present in c. - * - * @return Returns the number of removed elements. - */ - public int removeAll(ByteLookupContainer c); - - /** - * Removes all elements in this collection for which the given predicate returns true - * . - * - * @return Returns the number of removed elements. - */ - public int removeAll(BytePredicate predicate); - - /** - * Keeps all elements in this collection that are present in c. Runs in time - * proportional to the number of elements in this collection. Equivalent of sets intersection. - * - * @return Returns the number of removed elements. - */ - public int retainAll(ByteLookupContainer c); - - /** - * Keeps all elements in this collection for which the given predicate returns true. - * - * @return Returns the number of removed elements. - */ - public int retainAll(BytePredicate predicate); - - /** - * Removes all elements from this collection. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ByteContainer.java b/sources/main/java/com/carrotsearch/hppc/ByteContainer.java deleted file mode 100644 index 19edc86b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ByteContainer.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ByteCursor; -import com.carrotsearch.hppc.predicates.BytePredicate; -import com.carrotsearch.hppc.procedures.ByteProcedure; -import java.util.Iterator; - -/** A generic container holding bytes. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") -public interface ByteContainer extends Iterable { - /** - * Returns an iterator to a cursor traversing the collection. The order of traversal is not - * defined. More than one cursor may be active at a time. The behavior of iterators is undefined - * if structural changes are made to the underlying collection. - * - *

The iterator is implemented as a cursor and it returns the same cursor instance on - * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current - * list's value (or index in the list) use the cursor's public fields. An example is shown below. - * - *

-   * for (ByteCursor<byte> c : container) {
-   *   System.out.println("index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator(); - - /** - * Lookup a given element in the container. This operation has no speed guarantees (may be linear - * with respect to the size of this container). - * - * @return Returns true if this container has an element equal to e. - */ - public boolean contains(byte e); - - /** - * Return the current number of elements in this container. The time for calculating the - * container's size may take O(n) time, although implementing classes should try to - * maintain the current size and return in constant time. - */ - public int size(); - - /** Shortcut for size() == 0. */ - public boolean isEmpty(); - - /** - * Copies all elements of this container to an array. - * - *

The returned array is always a copy, regardless of the storage used by the container. - */ - public byte[] toArray(); - - /** - * Applies a procedure to all container elements. Returns the argument (any subclass - * of {@link ByteProcedure}. This lets the caller to call methods of the argument by chaining the - * call (even if the argument is an anonymous type) to retrieve computed values, for example - * (IntContainer): - * - *

-   * int count = container.forEach(new IntProcedure() {
-   *   int count; // this is a field declaration in an anonymous class.
-   *
-   *   public void apply(int value) {
-   *     count++;
-   *   }
-   * }).count;
-   * 
- */ - public T forEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T forEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ByteDeque.java b/sources/main/java/com/carrotsearch/hppc/ByteDeque.java deleted file mode 100644 index 3b8dd7fe..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ByteDeque.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ByteCursor; -import com.carrotsearch.hppc.predicates.BytePredicate; -import com.carrotsearch.hppc.procedures.ByteProcedure; -import java.util.Deque; -import java.util.Iterator; - -/** - * A linear collection that supports element insertion and removal at both ends. - * - * @see Deque - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") -public interface ByteDeque extends ByteCollection { - /** - * Removes the first element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeFirst(byte e); - - /** - * Removes the last element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeLast(byte e); - - /** Inserts the specified element at the front of this deque. */ - public void addFirst(byte e); - - /** Inserts the specified element at the end of this deque. */ - public void addLast(byte e); - - /** - * Retrieves and removes the first element of this deque. - * - * @return the head (first) element of this deque. - */ - public byte removeFirst(); - - /** - * Retrieves and removes the last element of this deque. - * - * @return the tail of this deque. - */ - public byte removeLast(); - - /** - * Retrieves the first element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public byte getFirst(); - - /** - * Retrieves the last element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public byte getLast(); - - /** - * @return An iterator over elements in this deque in tail-to-head order. - */ - public Iterator descendingIterator(); - - /** Applies a procedure to all elements in tail-to-head order. */ - public T descendingForEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T descendingForEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ByteIndexedContainer.java b/sources/main/java/com/carrotsearch/hppc/ByteIndexedContainer.java deleted file mode 100644 index f70fb895..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ByteIndexedContainer.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.carrotsearch.hppc; - -import java.util.RandomAccess; - -/** - * An indexed container provides random access to elements based on an index. Indexes - * are zero-based. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeIndexedContainer.java") -public interface ByteIndexedContainer extends ByteCollection, RandomAccess { - /** - * Removes the first element that equals e1, returning whether an element has been - * removed. - */ - public boolean removeElement(byte e1); - - /** - * Removes the first element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeFirst(byte e1); - - /** - * Removes the last element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeLast(byte e1); - - /** - * Returns the index of the first occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int indexOf(byte e1); - - /** - * Returns the index of the last occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int lastIndexOf(byte e1); - - /** Adds an element to the end of this container (the last index is incremented by one). */ - public void add(byte e1); - - /** - * Inserts the specified element at the specified position in this list. - * - * @param index The index at which the element should be inserted, shifting any existing and - * subsequent elements to the right. - */ - public void insert(int index, byte e1); - - /** - * Replaces the element at the specified position in this list with the specified element. - * - * @return Returns the previous value in the list. - */ - public byte set(int index, byte e1); - - /** - * @return Returns the element at index index from the list. - */ - public byte get(int index); - - /** - * Removes the element at the specified position in this container and returns it. - * - * @see #removeFirst - * @see #removeLast - * @see #removeAll - */ - public byte removeAt(int index); - - /** Removes and returns the last element of this container. This container must not be empty. */ - public byte removeLast(); - - /** - * Removes from this container all of the elements with indexes between fromIndex, - * inclusive, and toIndex, exclusive. - */ - public void removeRange(int fromIndex, int toIndex); - - /** Returns this container elements as a stream. */ - - /** Sorts the elements in this container and returns this container. */ - public ByteIndexedContainer sort(); - - /** Reverses the elements in this container and returns this container. */ - public ByteIndexedContainer reverse(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ByteLookupContainer.java b/sources/main/java/com/carrotsearch/hppc/ByteLookupContainer.java deleted file mode 100644 index ac41bc0b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ByteLookupContainer.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Marker interface for containers that can check if they contain a given object in at least time - * O(log n) and ideally in amortized constant time O(1). - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeLookupContainer.java") -public interface ByteLookupContainer extends ByteContainer { - public boolean contains(byte e); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ByteStack.java b/sources/main/java/com/carrotsearch/hppc/ByteStack.java deleted file mode 100644 index 0cf32432..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ByteStack.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ByteCursor; - -/** - * A subclass of {@link ByteArrayList} adding stack-related utility methods. The top of the stack is - * at the {@link #size()} - 1 element. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") -public class ByteStack extends ByteArrayList { - /** New instance with sane defaults. */ - public ByteStack() { - super(); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ByteStack(int expectedElements) { - super(expectedElements); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public ByteStack(int expectedElements, ArraySizingStrategy resizer) { - super(expectedElements, resizer); - } - - /** Create a stack by pushing all elements of another container to it. */ - public ByteStack(ByteContainer container) { - super(container); - } - - /** Adds one byte to the stack. */ - public void push(byte e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** Adds two bytes to the stack. */ - public void push(byte e1, byte e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Adds three bytes to the stack. */ - public void push(byte e1, byte e2, byte e3) { - ensureBufferSpace(3); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - } - - /** Adds four bytes to the stack. */ - public void push(byte e1, byte e2, byte e3, byte e4) { - ensureBufferSpace(4); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - buffer[elementsCount++] = e4; - } - - /** Add a range of array elements to the stack. */ - public void push(byte[] elements, int start, int len) { - assert start >= 0 && len >= 0; - - ensureBufferSpace(len); - System.arraycopy(elements, start, buffer, elementsCount, len); - elementsCount += len; - } - - /** - * Vararg-signature method for pushing elements at the top of the stack. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void push(byte... elements) { - push(elements, 0, elements.length); - } - - /** Pushes all elements from another container to the top of the stack. */ - public int pushAll(ByteContainer container) { - return addAll(container); - } - - /** Pushes all elements from another iterable to the top of the stack. */ - public int pushAll(Iterable iterable) { - return addAll(iterable); - } - - /** Discard an arbitrary number of elements from the top of the stack. */ - public void discard(int count) { - assert elementsCount >= count; - - elementsCount -= count; - } - - /** Discard the top element from the stack. */ - public void discard() { - assert elementsCount > 0; - - elementsCount--; - } - - /** Remove the top element from the stack and return it. */ - public byte pop() { - return removeLast(); - } - - /** Peek at the top element on the stack. */ - public byte peek() { - assert elementsCount > 0; - return buffer[elementsCount - 1]; - } - - /** Create a stack by pushing a variable number of arguments to it. */ - public static ByteStack from(byte... elements) { - final ByteStack stack = new ByteStack(elements.length); - stack.push(elements); - return stack; - } - - /** {@inheritDoc} */ - @Override - public ByteStack clone() { - return (ByteStack) super.clone(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharArrayDeque.java b/sources/main/java/com/carrotsearch/hppc/CharArrayDeque.java deleted file mode 100644 index e8aeb6a4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharArrayDeque.java +++ /dev/null @@ -1,776 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.CharCursor; -import com.carrotsearch.hppc.predicates.CharPredicate; -import com.carrotsearch.hppc.procedures.CharProcedure; -import java.util.*; - -/** An array-backed {@link CharDeque}. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") -public class CharArrayDeque extends AbstractCharCollection - implements CharDeque, Preallocable, Cloneable, Accountable { - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** Internal array for storing elements of the deque. */ - public char[] buffer = CharArrayList.EMPTY_ARRAY; - - /** - * The index of the element at the head of the deque or an arbitrary number equal to tail if the - * deque is empty. - */ - public int head; - - /** The index at which the next element would be added to the tail of the deque. */ - public int tail; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public CharArrayDeque() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharArrayDeque(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public CharArrayDeque(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - ensureCapacity(expectedElements); - } - - /** - * Creates a new deque from elements of another container, appending elements at the end of the - * deque in the iteration order. - */ - public CharArrayDeque(CharContainer container) { - this(container.size()); - addLast(container); - } - - /** {@inheritDoc} */ - @Override - public void addFirst(char e1) { - int h = oneLeft(head, buffer.length); - if (h == tail) { - ensureBufferSpace(1); - h = oneLeft(head, buffer.length); - } - buffer[head = h] = e1; - } - - /** - * Vararg-signature method for adding elements at the front of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to add. - */ - public final void addFirst(char... elements) { - ensureBufferSpace(elements.length); - for (char k : elements) { - addFirst(k); - } - } - - /** - * Inserts all elements from the given container to the front of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(CharContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (CharCursor cursor : container) { - addFirst(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the front of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(Iterable iterable) { - int size = 0; - for (CharCursor cursor : iterable) { - addFirst(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void addLast(char e1) { - int t = oneRight(tail, buffer.length); - if (head == t) { - ensureBufferSpace(1); - t = oneRight(tail, buffer.length); - } - buffer[tail] = e1; - tail = t; - } - - /** - * Vararg-signature method for adding elements at the end of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to iterate over. - */ - public final void addLast(char... elements) { - ensureBufferSpace(1); - for (char k : elements) { - addLast(k); - } - } - - /** - * Inserts all elements from the given container to the end of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(CharContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (CharCursor cursor : container) { - addLast(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the end of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(Iterable iterable) { - int size = 0; - for (CharCursor cursor : iterable) { - addLast(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public char removeFirst() { - assert size() > 0 : "The deque is empty."; - - final char result = buffer[head]; - buffer[head] = ((char) 0); - head = oneRight(head, buffer.length); - return result; - } - - /** {@inheritDoc} */ - @Override - public char removeLast() { - assert size() > 0 : "The deque is empty."; - - tail = oneLeft(tail, buffer.length); - final char result = buffer[tail]; - buffer[tail] = ((char) 0); - return result; - } - - /** {@inheritDoc} */ - @Override - public char getFirst() { - assert size() > 0 : "The deque is empty."; - - return buffer[head]; - } - - /** {@inheritDoc} */ - @Override - public char getLast() { - assert size() > 0 : "The deque is empty."; - - return buffer[oneLeft(tail, buffer.length)]; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(char e1) { - final int index = bufferIndexOf(e1); - if (index >= 0) removeAtBufferIndex(index); - return index; - } - - /** - * Return the index of the first (counting from head) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int bufferIndexOf(char e1) { - final int last = tail; - final int bufLen = buffer.length; - for (int i = head; i != last; i = oneRight(i, bufLen)) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(char e1) { - final int index = lastBufferIndexOf(e1); - if (index >= 0) { - removeAtBufferIndex(index); - } - return index; - } - - /** - * Return the index of the last (counting from tail) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int lastBufferIndexOf(char e1) { - final int bufLen = buffer.length; - final int last = oneLeft(head, bufLen); - for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { - if (((e1) == (buffer[i]))) return i; - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(char e1) { - int removed = 0; - final int last = tail; - final int bufLen = buffer.length; - int from, to; - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (((e1) == (buffer[from]))) { - buffer[from] = ((char) 0); - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((char) 0); - } - - to = oneRight(to, bufLen); - } - - tail = to; - return removed; - } - - /** - * Removes the element at index in the internal {#link {@link #buffer} array, - * returning its value. - * - * @param index Index of the element to remove. The index must be located between {@link #head} - * and {@link #tail} in modulo {@link #buffer} arithmetic. - */ - public void removeAtBufferIndex(int index) { - assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) - : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; - - // Cache fields in locals (hopefully moved to registers). - final char[] buffer = this.buffer; - final int bufLen = buffer.length; - final int lastIndex = bufLen - 1; - final int head = this.head; - final int tail = this.tail; - - final int leftChunk = Math.abs(index - head) % bufLen; - final int rightChunk = Math.abs(tail - index) % bufLen; - - if (leftChunk < rightChunk) { - if (index >= head) { - System.arraycopy(buffer, head, buffer, head + 1, leftChunk); - } else { - System.arraycopy(buffer, 0, buffer, 1, index); - buffer[0] = buffer[lastIndex]; - System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); - } - buffer[head] = ((char) 0); - this.head = oneRight(head, bufLen); - } else { - if (index < tail) { - System.arraycopy(buffer, index + 1, buffer, index, rightChunk); - } else { - System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); - buffer[lastIndex] = buffer[0]; - System.arraycopy(buffer, 1, buffer, 0, tail); - } - buffer[tail] = ((char) 0); - this.tail = oneLeft(tail, bufLen); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int size() { - if (head <= tail) return tail - head; - else return (tail - head + buffer.length); - } - - /** - * {@inheritDoc} - * - *

The internal array buffers are not released as a result of this call. - * - * @see #release() - */ - @Override - public void clear() { - if (head < tail) { - Arrays.fill(buffer, head, tail, ((char) 0)); - } else { - Arrays.fill(buffer, 0, tail, ((char) 0)); - Arrays.fill(buffer, head, buffer.length, ((char) 0)); - } - this.head = tail = 0; - } - - /** Release internal buffers of this deque and reallocate with the default buffer. */ - public void release() { - this.head = tail = 0; - buffer = CharArrayList.EMPTY_ARRAY; - ensureBufferSpace(0); - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - ensureBufferSpace(expectedElements - size()); - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = buffer.length; - final int elementsCount = size(); - - if (elementsCount + expectedAdditions >= bufferLen) { - final int emptySlot = 1; // deque invariant: always an empty slot. - final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); - assert newSize >= (elementsCount + expectedAdditions + emptySlot) - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - try { - final char[] newBuffer = (new char[newSize]); - if (bufferLen > 0) { - toArray(newBuffer); - tail = elementsCount; - head = 0; - } - this.buffer = newBuffer; - } catch (OutOfMemoryError e) { - throw new BufferAllocationException( - "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); - } - } - } - - /** {@inheritDoc} */ - @Override - public char[] toArray() { - - final int size = size(); - return toArray((new char[size])); - } - - /** - * Copies elements of this deque to an array. The content of the target array is - * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). - * - * @param target The target array must be large enough to hold all elements. - * @return Returns the target argument for chaining. - */ - public char[] toArray(char[] target) { - assert target.length >= size() : "Target array must be >= " + size(); - - if (head < tail) { - // The contents is not wrapped around. Just copy. - System.arraycopy(buffer, head, target, 0, size()); - } else if (head > tail) { - // The contents is split. Merge elements from the following indexes: - // [head...buffer.length - 1][0, tail - 1] - final int rightCount = buffer.length - head; - System.arraycopy(buffer, head, target, 0, rightCount); - System.arraycopy(buffer, 0, target, rightCount, tail); - } - - return target; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public CharArrayDeque clone() { - try { - - CharArrayDeque cloned = (CharArrayDeque) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Move one index to the left, wrapping around buffer. */ - protected static int oneLeft(int index, int modulus) { - if (index >= 1) { - return index - 1; - } - return modulus - 1; - } - - /** Move one index to the right, wrapping around buffer. */ - protected static int oneRight(int index, int modulus) { - if (index + 1 == modulus) { - return 0; - } - return index + 1; - } - - @Override - public long ramBytesAllocated() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); - } - - /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ - private final class ValueIterator extends AbstractIterator { - private final CharCursor cursor; - private int remaining; - - public ValueIterator() { - cursor = new CharCursor(); - cursor.index = oneLeft(head, buffer.length); - this.remaining = size(); - } - - @Override - protected CharCursor fetch() { - if (remaining == 0) { - return done(); - } - - remaining--; - cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; - return cursor; - } - } - - /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ - private final class DescendingValueIterator extends AbstractIterator { - private final CharCursor cursor; - private int remaining; - - public DescendingValueIterator() { - cursor = new CharCursor(); - cursor.index = tail; - this.remaining = size(); - } - - @Override - protected CharCursor fetch() { - if (remaining == 0) return done(); - - remaining--; - cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; - return cursor; - } - } - - /** - * Returns a cursor over the values of this deque (in head to tail order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *

-   * for (IntValueCursor c : intDeque) {
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator() { - return new ValueIterator(); - } - - /** - * Returns a cursor over the values of this deque (in tail to head order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *
-   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
-   *   final IntCursor c = i.next();
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator descendingIterator() { - return new DescendingValueIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - forEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, fromIndex, inclusive, to - * toIndex, exclusive. - */ - private void forEach(CharProcedure procedure, int fromIndex, final int toIndex) { - final char[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - procedure.apply(buffer[i]); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - int fromIndex = head; - int toIndex = tail; - - final char[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (!predicate.apply(buffer[i])) { - break; - } - } - - return predicate; - } - - /** Applies procedure to all elements of this deque, tail to head. */ - @Override - public T descendingForEach(T procedure) { - descendingForEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive. - */ - private void descendingForEach(CharProcedure procedure, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final char[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - procedure.apply(buffer[i]); - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public T descendingForEach(T predicate) { - descendingForEach(predicate, head, tail); - return predicate; - } - - /** - * Applies predicate to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive or until the predicate returns false. - */ - private void descendingForEach(CharPredicate predicate, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final char[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - if (!predicate.apply(buffer[i])) { - break; - } - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - final char[] buffer = this.buffer; - final int last = tail; - final int bufLen = buffer.length; - int removed = 0; - int from, to; - from = to = head; - try { - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (predicate.apply(buffer[from])) { - buffer[from] = ((char) 0); - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((char) 0); - } - - to = oneRight(to, bufLen); - } - } finally { - // Keep the deque in consistent state even if the predicate throws an exception. - for (; from != last; from = oneRight(from, bufLen)) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((char) 0); - } - - to = oneRight(to, bufLen); - } - tail = to; - } - - return removed; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(char e) { - int fromIndex = head; - int toIndex = tail; - - final char[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (((e) == (buffer[i]))) { - return true; - } - } - - return false; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1; - int fromIndex = head; - int toIndex = tail; - - final char[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare order-aligned elements against another {@link CharDeque}. */ - protected boolean equalElements(CharArrayDeque other) { - int max = size(); - if (other.size() != max) { - return false; - } - - Iterator i1 = this.iterator(); - Iterator i2 = other.iterator(); - - while (i1.hasNext() && i2.hasNext()) { - if (!((i1.next().value) == (i2.next().value))) { - return false; - } - } - - return !i1.hasNext() && !i2.hasNext(); - } - - /** Create a new deque by pushing a variable number of arguments to the end of it. */ - public static CharArrayDeque from(char... elements) { - final CharArrayDeque coll = new CharArrayDeque(elements.length); - coll.addLast(elements); - return coll; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharArrayList.java b/sources/main/java/com/carrotsearch/hppc/CharArrayList.java deleted file mode 100644 index 90837d31..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharArrayList.java +++ /dev/null @@ -1,579 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.CharPredicate; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** An array-backed list of chars. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") -public class CharArrayList extends AbstractCharCollection - implements CharIndexedContainer, Preallocable, Cloneable, Accountable { - /** An immutable empty buffer (array). */ - public static final char[] EMPTY_ARRAY = new char[0]; - - ; - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** - * Internal array for storing the list. The array may be larger than the current size ({@link - * #size()}). - */ - public char[] buffer = EMPTY_ARRAY; - - /** Current number of elements stored in {@link #buffer}. */ - public int elementsCount; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public CharArrayList() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharArrayList(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public CharArrayList(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - buffer = Arrays.copyOf(buffer, expectedElements); - } - - /** Creates a new list from the elements of another container in its iteration order. */ - public CharArrayList(CharContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public void add(char e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** - * Appends two elements at the end of the list. To add more than two elements, use add - * (vararg-version) or access the buffer directly (tight loop). - */ - public void add(char e1, char e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Add all elements from a range of given array to the list. */ - public void add(char[] elements, int start, int length) { - assert length >= 0 : "Length must be >= 0"; - - ensureBufferSpace(length); - System.arraycopy(elements, start, buffer, elementsCount, length); - elementsCount += length; - } - - /** - * Vararg-signature method for adding elements at the end of the list. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void add(char... elements) { - add(elements, 0, elements.length); - } - - /** Adds all elements from another container. */ - public int addAll(CharContainer container) { - final int size = container.size(); - ensureBufferSpace(size); - - for (CharCursor cursor : container) { - add(cursor.value); - } - - return size; - } - - /** Adds all elements from another iterable. */ - public int addAll(Iterable iterable) { - int size = 0; - for (CharCursor cursor : iterable) { - add(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void insert(int index, char e1) { - assert (index >= 0 && index <= size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; - - ensureBufferSpace(1); - System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); - buffer[index] = e1; - elementsCount++; - } - - /** {@inheritDoc} */ - @Override - public char get(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - return buffer[index]; - } - - /** {@inheritDoc} */ - @Override - public char set(int index, char e1) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final char v = buffer[index]; - buffer[index] = e1; - return v; - } - - /** {@inheritDoc} */ - @Override - public char removeAt(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final char v = buffer[index]; - System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); - - return v; - } - - /** {@inheritDoc} */ - @Override - public char removeLast() { - assert elementsCount > 0; - - final char v = buffer[--elementsCount]; - - return v; - } - - /** {@inheritDoc} */ - @Override - public void removeRange(int fromIndex, int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); - final int count = toIndex - fromIndex; - elementsCount -= count; - } - - /** {@inheritDoc} */ - @Override - public boolean removeElement(char e1) { - return removeFirst(e1) != -1; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(char e1) { - final int index = indexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(char e1) { - final int index = lastIndexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(char e1) { - int to = 0; - for (int from = 0; from < elementsCount; from++) { - if (((e1) == (buffer[from]))) { - continue; - } - if (to != from) { - buffer[to] = buffer[from]; - } - to++; - } - final int deleted = elementsCount - to; - this.elementsCount = to; - - return deleted; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(char e1) { - return indexOf(e1) >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexOf(char e1) { - for (int i = 0; i < elementsCount; i++) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int lastIndexOf(char e1) { - for (int i = elementsCount - 1; i >= 0; i--) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return elementsCount == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (expectedElements > bufferLen) { - ensureBufferSpace(expectedElements - size()); - } - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (elementsCount + expectedAdditions > bufferLen) { - final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); - assert newSize >= elementsCount + expectedAdditions - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - this.buffer = Arrays.copyOf(buffer, newSize); - } - } - - /** - * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be - * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated - * values will be reset to the default value (zero). If the list is expanded, the elements beyond - * the current size are initialized with JVM-defaults (zero or null values). - */ - public void resize(int newSize) { - if (newSize <= buffer.length) { - if (newSize < elementsCount) { - Arrays.fill(buffer, newSize, elementsCount, ((char) 0)); - } else { - Arrays.fill(buffer, elementsCount, newSize, ((char) 0)); - } - } else { - ensureCapacity(newSize); - } - this.elementsCount = newSize; - } - - /** {@inheritDoc} */ - @Override - public int size() { - return elementsCount; - } - - /** Trim the internal buffer to the current size. */ - public void trimToSize() { - if (size() != this.buffer.length) { - this.buffer = toArray(); - } - } - - /** - * Sets the number of stored elements to zero. Releases and initializes the internal storage array - * to default values. To clear the list without cleaning the buffer, simply set the {@link - * #elementsCount} field to zero. - */ - @Override - public void clear() { - Arrays.fill(buffer, 0, elementsCount, ((char) 0)); - this.elementsCount = 0; - } - - /** Sets the number of stored elements to zero and releases the internal storage array. */ - @Override - public void release() { - this.buffer = EMPTY_ARRAY; - this.elementsCount = 0; - } - - /** - * {@inheritDoc} - * - *

The returned array is sized to match exactly the number of elements of the stack. - */ - @Override - public char[] toArray() { - - return Arrays.copyOf(buffer, elementsCount); - } - - /** {@inheritDoc} */ - @Override - public CharIndexedContainer sort() { - Arrays.sort(buffer, 0, elementsCount); - return this; - } - - /** {@inheritDoc} */ - @Override - public CharIndexedContainer reverse() { - for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { - char tmp = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = tmp; - } - return this; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public CharArrayList clone() { - try { - - final CharArrayList cloned = (CharArrayList) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1, max = elementsCount; - for (int i = 0; i < max; i++) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare index-aligned elements against another {@link CharIndexedContainer}. */ - protected boolean equalElements(CharArrayList other) { - int max = size(); - if (other.size() != max) { - return false; - } - - for (int i = 0; i < max; i++) { - if (!((get(i)) == (other.get(i)))) { - return false; - } - } - - return true; - } - - @Override - public long ramBytesAllocated() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); - } - - /** An iterator implementation for {@link CharArrayList#iterator}. */ - static final class ValueIterator extends AbstractIterator { - private final CharCursor cursor; - - private final char[] buffer; - private final int size; - - public ValueIterator(char[] buffer, int size) { - this.cursor = new CharCursor(); - this.cursor.index = -1; - this.size = size; - this.buffer = buffer; - } - - @Override - protected CharCursor fetch() { - if (cursor.index + 1 == size) return done(); - - cursor.value = buffer[++cursor.index]; - return cursor; - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new ValueIterator(buffer, size()); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - return forEach(procedure, 0, size()); - } - - /** - * Applies procedure to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive. - */ - public T forEach(T procedure, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final char[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - procedure.apply(buffer[i]); - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - final char[] buffer = this.buffer; - final int elementsCount = this.elementsCount; - int to = 0; - int from = 0; - try { - for (; from < elementsCount; from++) { - if (predicate.apply(buffer[from])) { - buffer[from] = ((char) 0); - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((char) 0); - } - to++; - } - } finally { - // Keep the list in a consistent state, even if the predicate throws an exception. - for (; from < elementsCount; from++) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((char) 0); - } - to++; - } - - this.elementsCount = to; - } - - return elementsCount - to; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - return forEach(predicate, 0, size()); - } - - /** - * Applies predicate to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive, or until predicate returns false. - */ - public T forEach(T predicate, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final char[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - if (!predicate.apply(buffer[i])) break; - } - - return predicate; - } - - /** - * Create a list from a variable number of arguments or an array of char. The - * elements are copied from the argument to the internal buffer. - */ - public static CharArrayList from(char... elements) { - final CharArrayList list = new CharArrayList(elements.length); - list.add(elements); - return list; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharBufferVisualizer.java b/sources/main/java/com/carrotsearch/hppc/CharBufferVisualizer.java deleted file mode 100644 index 7bd17436..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharBufferVisualizer.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Reused buffer visualization routines. - * - * @see CharSet#visualizeKeyDistribution(int) - * @see CharVTypeMap#visualizeKeyDistribution(int) - */ -class CharBufferVisualizer { - static String visualizeKeyDistribution(char[] buffer, int max, int characters) { - final StringBuilder b = new StringBuilder(); - final char[] chars = ".123456789X".toCharArray(); - for (int i = 1, start = -1; i <= characters; i++) { - int end = (int) ((long) i * max / characters); - - if (start + 1 <= end) { - int taken = 0; - int slots = 0; - for (int slot = start + 1; slot <= end; slot++, slots++) { - if (!((buffer[slot]) == 0)) { - taken++; - } - } - b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); - start = end; - } - } - while (b.length() < characters) { - b.append(' '); - } - return b.toString(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharByteAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/CharByteAssociativeContainer.java deleted file mode 100644 index a69b4beb..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharByteAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see CharContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface CharByteAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(char key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharBytePredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharByteProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharBytePredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public CharCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ByteContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharByteHashMap.java b/sources/main/java/com/carrotsearch/hppc/CharByteHashMap.java deleted file mode 100644 index 93dd3c8f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharByteHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of char to byte, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class CharByteHashMap implements CharByteMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public char[] keys; - - /** The array holding values. */ - public byte[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public CharByteHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharByteHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public CharByteHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public CharByteHashMap(CharByteAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public byte put(char key, byte value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - byte previousValue = hasEmptyKey ? values[mask + 1] : ((byte) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final byte previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(CharByteAssociativeContainer container) { - final int count = size(); - for (CharByteCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (CharByteCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public byte putOrAdd(char key, byte putValue, byte incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((byte) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public byte addTo(char key, byte incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public byte remove(char key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((byte) 0); - } - hasEmptyKey = false; - byte previousValue = values[mask + 1]; - values[mask + 1] = ((byte) 0); - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final byte previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof CharLookupContainer) { - if (hasEmptyKey && other.contains(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (CharCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharBytePredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((char) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - } - - final char[] keys = this.keys; - final byte[] values = this.values; - for (int slot = 0; slot <= mask; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public byte get(char key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((byte) 0); - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public byte getOrDefault(char key, byte defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(char key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(char key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public byte indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public byte indexReplace(int index, byte newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - byte previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, char key, byte value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public byte indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - byte previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((byte) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((char) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (CharByteCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(CharByteHashMap other) { - if (other.size() != size()) { - return false; - } - - for (CharByteCursor c : other) { - char key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final char[] prevKeys = this.keys; - final byte[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharByteCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new CharByteCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharByteCursor fetch() { - final int mask = CharByteHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((char) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final char[] keys = this.keys; - final byte[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((char) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final char[] keys = this.keys; - final byte[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((char) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final CharByteHashMap owner = CharByteHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharByteProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharBytePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(CharPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final char e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = CharByteHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((char) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ByteCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractByteCollection { - private final CharByteHashMap owner = CharByteHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(byte value) { - for (CharByteCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (CharByteCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (CharByteCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final byte e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final BytePredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ByteCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ByteCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ByteCursor fetch() { - final int mask = CharByteHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public CharByteHashMap clone() { - try { - - CharByteHashMap cloned = (CharByteHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (CharByteCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static CharByteHashMap from(char[] keys, byte[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - CharByteHashMap map = new CharByteHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(char key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(char[] fromKeys, byte[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final char[] keys = this.keys; - final byte[] values = this.values; - final int mask = this.mask; - char existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - char[] prevKeys = this.keys; - byte[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new char[arraySize + emptyElementSlot]); - this.values = (new byte[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, char pendingKey, byte pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final char[] prevKeys = this.keys; - final byte[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final char[] keys = this.keys; - final byte[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final char existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((char) 0); - values[gapSlot] = ((byte) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharByteMap.java b/sources/main/java/com/carrotsearch/hppc/CharByteMap.java deleted file mode 100644 index dcb4ef54..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharByteMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharByteCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface CharByteMap extends CharByteAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public byte get(char key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public byte getOrDefault(char key, byte defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public byte put(char key, byte value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(char key, byte value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(CharByteAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public byte putOrAdd(char key, byte putValue, byte incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public byte addTo(char key, byte additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public byte remove(char key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link CharByteMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(char key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexReplace(int index, byte newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, char key, byte value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharCharAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/CharCharAssociativeContainer.java deleted file mode 100644 index b7334bbc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharCharAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see CharContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface CharCharAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(char key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharCharPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharCharProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharCharPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public CharCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public CharContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharCharHashMap.java b/sources/main/java/com/carrotsearch/hppc/CharCharHashMap.java deleted file mode 100644 index 509c1a2c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharCharHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of char to char, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class CharCharHashMap implements CharCharMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public char[] keys; - - /** The array holding values. */ - public char[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public CharCharHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharCharHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public CharCharHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public CharCharHashMap(CharCharAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public char put(char key, char value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - char previousValue = hasEmptyKey ? values[mask + 1] : ((char) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final char previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(CharCharAssociativeContainer container) { - final int count = size(); - for (CharCharCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (CharCharCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public char putOrAdd(char key, char putValue, char incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((char) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public char addTo(char key, char incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public char remove(char key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((char) 0); - } - hasEmptyKey = false; - char previousValue = values[mask + 1]; - values[mask + 1] = ((char) 0); - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final char previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof CharLookupContainer) { - if (hasEmptyKey && other.contains(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (CharCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharCharPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((char) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - } - - final char[] keys = this.keys; - final char[] values = this.values; - for (int slot = 0; slot <= mask; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public char get(char key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((char) 0); - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public char getOrDefault(char key, char defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(char key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(char key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public char indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public char indexReplace(int index, char newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - char previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, char key, char value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public char indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - char previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((char) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((char) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (CharCharCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(CharCharHashMap other) { - if (other.size() != size()) { - return false; - } - - for (CharCharCursor c : other) { - char key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final char[] prevKeys = this.keys; - final char[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharCharCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new CharCharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCharCursor fetch() { - final int mask = CharCharHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((char) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final char[] keys = this.keys; - final char[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((char) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final char[] keys = this.keys; - final char[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((char) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final CharCharHashMap owner = CharCharHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharCharProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharCharPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(CharPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final char e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = CharCharHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((char) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public CharCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractCharCollection { - private final CharCharHashMap owner = CharCharHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(char value) { - for (CharCharCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (CharCharCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (CharCharCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final char e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final CharPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = CharCharHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public CharCharHashMap clone() { - try { - - CharCharHashMap cloned = (CharCharHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (CharCharCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static CharCharHashMap from(char[] keys, char[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - CharCharHashMap map = new CharCharHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(char key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(char[] fromKeys, char[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final char[] keys = this.keys; - final char[] values = this.values; - final int mask = this.mask; - char existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - char[] prevKeys = this.keys; - char[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new char[arraySize + emptyElementSlot]); - this.values = (new char[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, char pendingKey, char pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final char[] prevKeys = this.keys; - final char[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final char[] keys = this.keys; - final char[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final char existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((char) 0); - values[gapSlot] = ((char) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharCharMap.java b/sources/main/java/com/carrotsearch/hppc/CharCharMap.java deleted file mode 100644 index c3690bba..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharCharMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharCharCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface CharCharMap extends CharCharAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public char get(char key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public char getOrDefault(char key, char defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public char put(char key, char value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(char key, char value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(CharCharAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public char putOrAdd(char key, char putValue, char incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public char addTo(char key, char additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public char remove(char key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link CharCharMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(char key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexReplace(int index, char newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, char key, char value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharCollection.java b/sources/main/java/com/carrotsearch/hppc/CharCollection.java deleted file mode 100644 index 4cc8517b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharCollection.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.predicates.CharPredicate; - -/** - * A collection allows basic, efficient operations on sets of elements (difference and - * intersection). - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") -public interface CharCollection extends CharContainer { - /** - * Removes all occurrences of e from this collection. - * - * @param e Element to be removed from this collection, if present. - * @return The number of removed elements as a result of this call. - */ - public int removeAll(char e); - - /** - * Removes all elements in this collection that are present in c. - * - * @return Returns the number of removed elements. - */ - public int removeAll(CharLookupContainer c); - - /** - * Removes all elements in this collection for which the given predicate returns true - * . - * - * @return Returns the number of removed elements. - */ - public int removeAll(CharPredicate predicate); - - /** - * Keeps all elements in this collection that are present in c. Runs in time - * proportional to the number of elements in this collection. Equivalent of sets intersection. - * - * @return Returns the number of removed elements. - */ - public int retainAll(CharLookupContainer c); - - /** - * Keeps all elements in this collection for which the given predicate returns true. - * - * @return Returns the number of removed elements. - */ - public int retainAll(CharPredicate predicate); - - /** - * Removes all elements from this collection. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharContainer.java b/sources/main/java/com/carrotsearch/hppc/CharContainer.java deleted file mode 100644 index 5977583b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharContainer.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharCursor; -import com.carrotsearch.hppc.predicates.CharPredicate; -import com.carrotsearch.hppc.procedures.CharProcedure; -import java.util.Iterator; - -/** A generic container holding chars. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") -public interface CharContainer extends Iterable { - /** - * Returns an iterator to a cursor traversing the collection. The order of traversal is not - * defined. More than one cursor may be active at a time. The behavior of iterators is undefined - * if structural changes are made to the underlying collection. - * - *

The iterator is implemented as a cursor and it returns the same cursor instance on - * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current - * list's value (or index in the list) use the cursor's public fields. An example is shown below. - * - *

-   * for (CharCursor<char> c : container) {
-   *   System.out.println("index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator(); - - /** - * Lookup a given element in the container. This operation has no speed guarantees (may be linear - * with respect to the size of this container). - * - * @return Returns true if this container has an element equal to e. - */ - public boolean contains(char e); - - /** - * Return the current number of elements in this container. The time for calculating the - * container's size may take O(n) time, although implementing classes should try to - * maintain the current size and return in constant time. - */ - public int size(); - - /** Shortcut for size() == 0. */ - public boolean isEmpty(); - - /** - * Copies all elements of this container to an array. - * - *

The returned array is always a copy, regardless of the storage used by the container. - */ - public char[] toArray(); - - /** - * Applies a procedure to all container elements. Returns the argument (any subclass - * of {@link CharProcedure}. This lets the caller to call methods of the argument by chaining the - * call (even if the argument is an anonymous type) to retrieve computed values, for example - * (IntContainer): - * - *

-   * int count = container.forEach(new IntProcedure() {
-   *   int count; // this is a field declaration in an anonymous class.
-   *
-   *   public void apply(int value) {
-   *     count++;
-   *   }
-   * }).count;
-   * 
- */ - public T forEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T forEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharDeque.java b/sources/main/java/com/carrotsearch/hppc/CharDeque.java deleted file mode 100644 index 34ff5c92..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharDeque.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharCursor; -import com.carrotsearch.hppc.predicates.CharPredicate; -import com.carrotsearch.hppc.procedures.CharProcedure; -import java.util.Deque; -import java.util.Iterator; - -/** - * A linear collection that supports element insertion and removal at both ends. - * - * @see Deque - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") -public interface CharDeque extends CharCollection { - /** - * Removes the first element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeFirst(char e); - - /** - * Removes the last element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeLast(char e); - - /** Inserts the specified element at the front of this deque. */ - public void addFirst(char e); - - /** Inserts the specified element at the end of this deque. */ - public void addLast(char e); - - /** - * Retrieves and removes the first element of this deque. - * - * @return the head (first) element of this deque. - */ - public char removeFirst(); - - /** - * Retrieves and removes the last element of this deque. - * - * @return the tail of this deque. - */ - public char removeLast(); - - /** - * Retrieves the first element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public char getFirst(); - - /** - * Retrieves the last element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public char getLast(); - - /** - * @return An iterator over elements in this deque in tail-to-head order. - */ - public Iterator descendingIterator(); - - /** Applies a procedure to all elements in tail-to-head order. */ - public T descendingForEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T descendingForEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharDoubleAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/CharDoubleAssociativeContainer.java deleted file mode 100644 index 2d898f2c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharDoubleAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see CharContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface CharDoubleAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *
-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(char key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharDoublePredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharDoubleProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharDoublePredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public CharCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public DoubleContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharDoubleHashMap.java b/sources/main/java/com/carrotsearch/hppc/CharDoubleHashMap.java deleted file mode 100644 index 0a68bfaf..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharDoubleHashMap.java +++ /dev/null @@ -1,1082 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of char to double, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class CharDoubleHashMap implements CharDoubleMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public char[] keys; - - /** The array holding values. */ - public double[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public CharDoubleHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharDoubleHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public CharDoubleHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public CharDoubleHashMap(CharDoubleAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public double put(char key, double value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - double previousValue = hasEmptyKey ? values[mask + 1] : 0d; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final double previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(CharDoubleAssociativeContainer container) { - final int count = size(); - for (CharDoubleCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (CharDoubleCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public double putOrAdd(char key, double putValue, double incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((double) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public double addTo(char key, double incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public double remove(char key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0d; - } - hasEmptyKey = false; - double previousValue = values[mask + 1]; - values[mask + 1] = 0d; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final double previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof CharLookupContainer) { - if (hasEmptyKey && other.contains(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (CharCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharDoublePredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((char) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - } - - final char[] keys = this.keys; - final double[] values = this.values; - for (int slot = 0; slot <= mask; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public double get(char key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0d; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public double getOrDefault(char key, double defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(char key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(char key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public double indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public double indexReplace(int index, double newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - double previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, char key, double value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public double indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - double previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0d; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((char) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (CharDoubleCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(CharDoubleHashMap other) { - if (other.size() != size()) { - return false; - } - - for (CharDoubleCursor c : other) { - char key = c.key; - if (!containsKey(key) - || !(Double.doubleToLongBits(c.value) == Double.doubleToLongBits(get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final char[] prevKeys = this.keys; - final double[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharDoubleCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new CharDoubleCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharDoubleCursor fetch() { - final int mask = CharDoubleHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((char) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final char[] keys = this.keys; - final double[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((char) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final char[] keys = this.keys; - final double[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((char) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final CharDoubleHashMap owner = CharDoubleHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharDoubleProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharDoublePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(CharPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final char e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = CharDoubleHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((char) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public DoubleCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractDoubleCollection { - private final CharDoubleHashMap owner = CharDoubleHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(double value) { - for (CharDoubleCursor c : owner) { - if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (CharDoubleCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (CharDoubleCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final double e) { - return owner.removeAll( - (key, value) -> (Double.doubleToLongBits(e) == Double.doubleToLongBits(value))); - } - - @Override - public int removeAll(final DoublePredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final DoubleCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new DoubleCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected DoubleCursor fetch() { - final int mask = CharDoubleHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public CharDoubleHashMap clone() { - try { - - CharDoubleHashMap cloned = (CharDoubleHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (CharDoubleCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static CharDoubleHashMap from(char[] keys, double[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - CharDoubleHashMap map = new CharDoubleHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(char key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(char[] fromKeys, double[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final char[] keys = this.keys; - final double[] values = this.values; - final int mask = this.mask; - char existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - char[] prevKeys = this.keys; - double[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new char[arraySize + emptyElementSlot]); - this.values = (new double[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, char pendingKey, double pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final char[] prevKeys = this.keys; - final double[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final char[] keys = this.keys; - final double[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final char existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((char) 0); - values[gapSlot] = 0d; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharDoubleMap.java b/sources/main/java/com/carrotsearch/hppc/CharDoubleMap.java deleted file mode 100644 index 2ba6e41b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharDoubleMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharDoubleCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface CharDoubleMap extends CharDoubleAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public double get(char key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public double getOrDefault(char key, double defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public double put(char key, double value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(char key, double value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(CharDoubleAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public double putOrAdd(char key, double putValue, double incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public double addTo(char key, double additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public double remove(char key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link CharDoubleMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(char key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexReplace(int index, double newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, char key, double value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharFloatAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/CharFloatAssociativeContainer.java deleted file mode 100644 index 10069a39..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharFloatAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see CharContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface CharFloatAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(char key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharFloatPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharFloatProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharFloatPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public CharCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public FloatContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharFloatHashMap.java b/sources/main/java/com/carrotsearch/hppc/CharFloatHashMap.java deleted file mode 100644 index 0f4d6d8f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharFloatHashMap.java +++ /dev/null @@ -1,1081 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of char to float, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class CharFloatHashMap implements CharFloatMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public char[] keys; - - /** The array holding values. */ - public float[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public CharFloatHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharFloatHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public CharFloatHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public CharFloatHashMap(CharFloatAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public float put(char key, float value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - float previousValue = hasEmptyKey ? values[mask + 1] : 0f; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final float previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(CharFloatAssociativeContainer container) { - final int count = size(); - for (CharFloatCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (CharFloatCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public float putOrAdd(char key, float putValue, float incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((float) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public float addTo(char key, float incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public float remove(char key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0f; - } - hasEmptyKey = false; - float previousValue = values[mask + 1]; - values[mask + 1] = 0f; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final float previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof CharLookupContainer) { - if (hasEmptyKey && other.contains(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (CharCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharFloatPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((char) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - } - - final char[] keys = this.keys; - final float[] values = this.values; - for (int slot = 0; slot <= mask; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public float get(char key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0f; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public float getOrDefault(char key, float defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(char key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(char key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public float indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public float indexReplace(int index, float newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - float previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, char key, float value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public float indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - float previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0f; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((char) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (CharFloatCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(CharFloatHashMap other) { - if (other.size() != size()) { - return false; - } - - for (CharFloatCursor c : other) { - char key = c.key; - if (!containsKey(key) || !(Float.floatToIntBits(c.value) == Float.floatToIntBits(get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final char[] prevKeys = this.keys; - final float[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharFloatCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new CharFloatCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharFloatCursor fetch() { - final int mask = CharFloatHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((char) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final char[] keys = this.keys; - final float[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((char) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final char[] keys = this.keys; - final float[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((char) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final CharFloatHashMap owner = CharFloatHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharFloatProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharFloatPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(CharPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final char e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = CharFloatHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((char) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public FloatCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractFloatCollection { - private final CharFloatHashMap owner = CharFloatHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(float value) { - for (CharFloatCursor c : owner) { - if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (CharFloatCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (CharFloatCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final float e) { - return owner.removeAll( - (key, value) -> (Float.floatToIntBits(e) == Float.floatToIntBits(value))); - } - - @Override - public int removeAll(final FloatPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final FloatCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new FloatCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected FloatCursor fetch() { - final int mask = CharFloatHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public CharFloatHashMap clone() { - try { - - CharFloatHashMap cloned = (CharFloatHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (CharFloatCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static CharFloatHashMap from(char[] keys, float[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - CharFloatHashMap map = new CharFloatHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(char key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(char[] fromKeys, float[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final char[] keys = this.keys; - final float[] values = this.values; - final int mask = this.mask; - char existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - char[] prevKeys = this.keys; - float[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new char[arraySize + emptyElementSlot]); - this.values = (new float[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, char pendingKey, float pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final char[] prevKeys = this.keys; - final float[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final char[] keys = this.keys; - final float[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final char existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((char) 0); - values[gapSlot] = 0f; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharFloatMap.java b/sources/main/java/com/carrotsearch/hppc/CharFloatMap.java deleted file mode 100644 index 4bf7569f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharFloatMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharFloatCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface CharFloatMap extends CharFloatAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public float get(char key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public float getOrDefault(char key, float defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public float put(char key, float value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(char key, float value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(CharFloatAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public float putOrAdd(char key, float putValue, float incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public float addTo(char key, float additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public float remove(char key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link CharFloatMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(char key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexReplace(int index, float newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, char key, float value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharHashSet.java b/sources/main/java/com/carrotsearch/hppc/CharHashSet.java deleted file mode 100644 index 58ad8f26..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharHashSet.java +++ /dev/null @@ -1,787 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash set of chars, implemented using open addressing with linear probing for - * collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java") -public class CharHashSet extends AbstractCharCollection - implements CharLookupContainer, CharSet, Preallocable, Cloneable, Accountable { - /** The hash array holding keys. */ - public char[] keys; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any. - * - * @see #size() - * @see #hasEmptyKey - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** - * New instance with sane defaults. - * - * @see #CharHashSet(int, double) - */ - public CharHashSet() { - this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with sane defaults. - * - * @see #CharHashSet(int, double) - */ - public CharHashSet(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public CharHashSet(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** New instance copying elements from another {@link CharContainer}. */ - public CharHashSet(CharContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public boolean add(char key) { - if (((key) == 0)) { - assert ((keys[mask + 1]) == 0); - boolean added = !hasEmptyKey; - hasEmptyKey = true; - return added; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return false; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key); - } else { - keys[slot] = key; - } - - assigned++; - return true; - } - } - - /** - * Adds all elements from the given list (vararg) to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public final int addAll(char... elements) { - ensureCapacity(elements.length); - int count = 0; - for (char e : elements) { - if (add(e)) { - count++; - } - } - return count; - } - - /** - * Adds all elements from the given {@link CharContainer} to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public int addAll(CharContainer container) { - ensureCapacity(container.size()); - return addAll((Iterable) container); - } - - /** - * Adds all elements from the given iterable to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public int addAll(Iterable iterable) { - int count = 0; - for (CharCursor cursor : iterable) { - if (add(cursor.value)) { - count++; - } - } - return count; - } - - /** {@inheritDoc} */ - @Override - public char[] toArray() { - - final char[] cloned = (new char[size()]); - int j = 0; - if (hasEmptyKey) { - cloned[j++] = ((char) 0); - } - - final char[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - char existing; - if (!((existing = keys[slot]) == 0)) { - cloned[j++] = existing; - } - } - - return cloned; - } - - /** An alias for the (preferred) {@link #removeAll}. */ - public boolean remove(char key) { - if (((key) == 0)) { - boolean hadEmptyKey = hasEmptyKey; - hasEmptyKey = false; - return hadEmptyKey; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - shiftConflictingKeys(slot); - return true; - } - slot = (slot + 1) & mask; - } - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(char key) { - return remove(key) ? 1 : 0; - } - - /** - * Removes all keys present in a given container. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharContainer other) { - final int before = size(); - - // Try to iterate over the smaller set or over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof CharLookupContainer) { - if (hasEmptyKey && other.contains(((char) 0))) { - hasEmptyKey = false; - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (CharCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((char) 0))) { - hasEmptyKey = false; - } - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0)) { - if (predicate.apply(existing)) { - shiftConflictingKeys(slot); - continue; // Repeat the check for the same slot i (shifted). - } - } - slot++; - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public boolean contains(char key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - return false; - } - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - Arrays.fill(keys, ((char) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - keys = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final char[] prevKeys = this.keys; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys); - } - } - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - final char[] keys = this.keys; - for (int slot = mask; slot >= 0; slot--) { - char existing; - if (!((existing = keys[slot]) == 0)) { - h += BitMixer.mix(existing); - } - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - private boolean sameKeys(CharSet other) { - if (other.size() != size()) { - return false; - } - - for (CharCursor c : other) { - if (!contains(c.value)) { - return false; - } - } - - return true; - } - - /** {@inheritDoc} */ - @Override - public CharHashSet clone() { - try { - - CharHashSet cloned = (CharHashSet) super.clone(); - cloned.keys = keys.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - @Override - public long ramBytesAllocated() { - // int: assigned, mask, keyMixer, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys); - } - - @Override - public long ramBytesUsed() { - // int: assigned, mask, keyMixer, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - protected final class EntryIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = CharHashSet.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((char) 0); - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - if (hasEmptyKey) { - procedure.apply(((char) 0)); - } - - final char[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - char existing; - if (!((existing = keys[slot]) == 0)) { - procedure.apply(existing); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - if (hasEmptyKey) { - if (!predicate.apply(((char) 0))) { - return predicate; - } - } - - final char[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - char existing; - if (!((existing = keys[slot]) == 0)) { - if (!predicate.apply(existing)) { - break; - } - } - } - - return predicate; - } - - /** - * Create a set from a variable number of arguments or an array of char. The elements - * are copied from the argument to the internal buffer. - */ - public static CharHashSet from(char... elements) { - final CharHashSet set = new CharHashSet(elements.length); - set.addAll(elements); - return set; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(char key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up logic in - * certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between modifications (it will not be affected by read-only - * operations). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the set. - * @return A non-negative value of the logical "index" of the key in the set or a negative value - * if the key did not exist. - */ - public int indexOf(char key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index) { - assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** - * Returns the exact value of the existing key. This method makes sense for sets of objects which - * define custom key-equality relationship. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the equivalent key currently stored in the set. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return keys[index]; - } - - /** - * Replaces the existing equivalent key with the given one and returns any previous value stored - * for that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key - * currently stored at the provided index. - * @return Returns the previous key stored in the set. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexReplace(int index, char equivalentKey) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - assert ((keys[index]) == (equivalentKey)); - - char previousValue = keys[index]; - keys[index] = equivalentKey; - return previousValue; - } - - /** - * Inserts a key for an index that is not present in the set. This method may help in avoiding - * double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public void indexInsert(int index, char key) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - assert ((keys[index]) == 0); - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key); - } else { - keys[index] = key; - } - - assigned++; - } - } - - /** - * Removes a key at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public void indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - if (index > mask) { - hasEmptyKey = false; - } else { - shiftConflictingKeys(index); - } - } - - @Override - public String visualizeKeyDistribution(int characters) { - return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(char[] fromKeys) { - assert HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored keys into the new buffers. - final char[] keys = this.keys; - final int mask = this.mask; - char existing; - for (int i = fromKeys.length - 1; --i >= 0; ) { - if (!((existing = fromKeys[i]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - char[] prevKeys = this.keys; - try { - int emptyElementSlot = 1; - this.keys = (new char[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.keys == null ? 0 : size(), arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key to be inserted into the buffer but there is not - * enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, char pendingKey) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final char[] prevKeys = this.keys; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - - // Rehash old keys, including the pending key. - rehash(prevKeys); - } - - /** Shift all the slot-conflicting keys allocated to (and including) slot. */ - protected void shiftConflictingKeys(int gapSlot) { - final char[] keys = this.keys; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final char existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((char) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharIndexedContainer.java b/sources/main/java/com/carrotsearch/hppc/CharIndexedContainer.java deleted file mode 100644 index 96824521..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharIndexedContainer.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.carrotsearch.hppc; - -import java.util.RandomAccess; - -/** - * An indexed container provides random access to elements based on an index. Indexes - * are zero-based. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeIndexedContainer.java") -public interface CharIndexedContainer extends CharCollection, RandomAccess { - /** - * Removes the first element that equals e1, returning whether an element has been - * removed. - */ - public boolean removeElement(char e1); - - /** - * Removes the first element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeFirst(char e1); - - /** - * Removes the last element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeLast(char e1); - - /** - * Returns the index of the first occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int indexOf(char e1); - - /** - * Returns the index of the last occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int lastIndexOf(char e1); - - /** Adds an element to the end of this container (the last index is incremented by one). */ - public void add(char e1); - - /** - * Inserts the specified element at the specified position in this list. - * - * @param index The index at which the element should be inserted, shifting any existing and - * subsequent elements to the right. - */ - public void insert(int index, char e1); - - /** - * Replaces the element at the specified position in this list with the specified element. - * - * @return Returns the previous value in the list. - */ - public char set(int index, char e1); - - /** - * @return Returns the element at index index from the list. - */ - public char get(int index); - - /** - * Removes the element at the specified position in this container and returns it. - * - * @see #removeFirst - * @see #removeLast - * @see #removeAll - */ - public char removeAt(int index); - - /** Removes and returns the last element of this container. This container must not be empty. */ - public char removeLast(); - - /** - * Removes from this container all of the elements with indexes between fromIndex, - * inclusive, and toIndex, exclusive. - */ - public void removeRange(int fromIndex, int toIndex); - - /** Returns this container elements as a stream. */ - - /** Sorts the elements in this container and returns this container. */ - public CharIndexedContainer sort(); - - /** Reverses the elements in this container and returns this container. */ - public CharIndexedContainer reverse(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharIntAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/CharIntAssociativeContainer.java deleted file mode 100644 index 08c5d64a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharIntAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see CharContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface CharIntAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(char key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharIntPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharIntProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharIntPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public CharCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public IntContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharIntHashMap.java b/sources/main/java/com/carrotsearch/hppc/CharIntHashMap.java deleted file mode 100644 index aff7e50d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharIntHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of char to int, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class CharIntHashMap implements CharIntMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public char[] keys; - - /** The array holding values. */ - public int[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public CharIntHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharIntHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public CharIntHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public CharIntHashMap(CharIntAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public int put(char key, int value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - int previousValue = hasEmptyKey ? values[mask + 1] : 0; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final int previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(CharIntAssociativeContainer container) { - final int count = size(); - for (CharIntCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (CharIntCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public int putOrAdd(char key, int putValue, int incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((int) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public int addTo(char key, int incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public int remove(char key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0; - } - hasEmptyKey = false; - int previousValue = values[mask + 1]; - values[mask + 1] = 0; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final int previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof CharLookupContainer) { - if (hasEmptyKey && other.contains(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (CharCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharIntPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((char) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - } - - final char[] keys = this.keys; - final int[] values = this.values; - for (int slot = 0; slot <= mask; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int get(char key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int getOrDefault(char key, int defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(char key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(char key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public int indexReplace(int index, int newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - int previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, char key, int value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public int indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - int previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((char) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (CharIntCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(CharIntHashMap other) { - if (other.size() != size()) { - return false; - } - - for (CharIntCursor c : other) { - char key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final char[] prevKeys = this.keys; - final int[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharIntCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new CharIntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharIntCursor fetch() { - final int mask = CharIntHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((char) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final char[] keys = this.keys; - final int[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((char) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final char[] keys = this.keys; - final int[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((char) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final CharIntHashMap owner = CharIntHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharIntProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharIntPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(CharPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final char e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = CharIntHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((char) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public IntCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractIntCollection { - private final CharIntHashMap owner = CharIntHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(int value) { - for (CharIntCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (CharIntCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (CharIntCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final int e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final IntPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = CharIntHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public CharIntHashMap clone() { - try { - - CharIntHashMap cloned = (CharIntHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (CharIntCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static CharIntHashMap from(char[] keys, int[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - CharIntHashMap map = new CharIntHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(char key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(char[] fromKeys, int[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final char[] keys = this.keys; - final int[] values = this.values; - final int mask = this.mask; - char existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - char[] prevKeys = this.keys; - int[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new char[arraySize + emptyElementSlot]); - this.values = (new int[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, char pendingKey, int pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final char[] prevKeys = this.keys; - final int[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final char[] keys = this.keys; - final int[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final char existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((char) 0); - values[gapSlot] = 0; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharIntMap.java b/sources/main/java/com/carrotsearch/hppc/CharIntMap.java deleted file mode 100644 index 8c2f24e0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharIntMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharIntCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface CharIntMap extends CharIntAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public int get(char key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public int getOrDefault(char key, int defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public int put(char key, int value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(char key, int value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(CharIntAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public int putOrAdd(char key, int putValue, int incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public int addTo(char key, int additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public int remove(char key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link CharIntMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(char key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexReplace(int index, int newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, char key, int value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharLongAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/CharLongAssociativeContainer.java deleted file mode 100644 index 7999c340..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharLongAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see CharContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface CharLongAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(char key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharLongPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharLongProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharLongPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public CharCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public LongContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharLongHashMap.java b/sources/main/java/com/carrotsearch/hppc/CharLongHashMap.java deleted file mode 100644 index e1bea344..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharLongHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of char to long, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class CharLongHashMap implements CharLongMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public char[] keys; - - /** The array holding values. */ - public long[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public CharLongHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharLongHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public CharLongHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public CharLongHashMap(CharLongAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public long put(char key, long value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - long previousValue = hasEmptyKey ? values[mask + 1] : 0L; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final long previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(CharLongAssociativeContainer container) { - final int count = size(); - for (CharLongCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (CharLongCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public long putOrAdd(char key, long putValue, long incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((long) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public long addTo(char key, long incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public long remove(char key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0L; - } - hasEmptyKey = false; - long previousValue = values[mask + 1]; - values[mask + 1] = 0L; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final long previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof CharLookupContainer) { - if (hasEmptyKey && other.contains(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (CharCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharLongPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((char) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - } - - final char[] keys = this.keys; - final long[] values = this.values; - for (int slot = 0; slot <= mask; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public long get(char key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0L; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public long getOrDefault(char key, long defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(char key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(char key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public long indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public long indexReplace(int index, long newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - long previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, char key, long value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public long indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - long previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0L; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((char) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (CharLongCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(CharLongHashMap other) { - if (other.size() != size()) { - return false; - } - - for (CharLongCursor c : other) { - char key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final char[] prevKeys = this.keys; - final long[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharLongCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new CharLongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharLongCursor fetch() { - final int mask = CharLongHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((char) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final char[] keys = this.keys; - final long[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((char) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final char[] keys = this.keys; - final long[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((char) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final CharLongHashMap owner = CharLongHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharLongProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharLongPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(CharPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final char e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = CharLongHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((char) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public LongCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractLongCollection { - private final CharLongHashMap owner = CharLongHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(long value) { - for (CharLongCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (CharLongCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (CharLongCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final long e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final LongPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = CharLongHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public CharLongHashMap clone() { - try { - - CharLongHashMap cloned = (CharLongHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (CharLongCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static CharLongHashMap from(char[] keys, long[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - CharLongHashMap map = new CharLongHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(char key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(char[] fromKeys, long[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final char[] keys = this.keys; - final long[] values = this.values; - final int mask = this.mask; - char existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - char[] prevKeys = this.keys; - long[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new char[arraySize + emptyElementSlot]); - this.values = (new long[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, char pendingKey, long pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final char[] prevKeys = this.keys; - final long[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final char[] keys = this.keys; - final long[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final char existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((char) 0); - values[gapSlot] = 0L; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharLongMap.java b/sources/main/java/com/carrotsearch/hppc/CharLongMap.java deleted file mode 100644 index fcbda2b4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharLongMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharLongCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface CharLongMap extends CharLongAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public long get(char key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public long getOrDefault(char key, long defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public long put(char key, long value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(char key, long value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(CharLongAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public long putOrAdd(char key, long putValue, long incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public long addTo(char key, long additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public long remove(char key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link CharLongMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(char key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexReplace(int index, long newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, char key, long value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharLookupContainer.java b/sources/main/java/com/carrotsearch/hppc/CharLookupContainer.java deleted file mode 100644 index 3e2fd0a4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharLookupContainer.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Marker interface for containers that can check if they contain a given object in at least time - * O(log n) and ideally in amortized constant time O(1). - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeLookupContainer.java") -public interface CharLookupContainer extends CharContainer { - public boolean contains(char e); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharObjectAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/CharObjectAssociativeContainer.java deleted file mode 100644 index 806efa68..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharObjectAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see CharContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface CharObjectAssociativeContainer extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(char key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharObjectPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharObjectProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharObjectPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public CharCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ObjectContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharObjectHashMap.java b/sources/main/java/com/carrotsearch/hppc/CharObjectHashMap.java deleted file mode 100644 index a9d9a0d5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharObjectHashMap.java +++ /dev/null @@ -1,1050 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of char to Object, implemented using open addressing with - * linear probing for collision resolution. Supports null values. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class CharObjectHashMap - implements CharObjectMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public char[] keys; - - /** The array holding values. */ - public Object[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public CharObjectHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharObjectHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public CharObjectHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public CharObjectHashMap(CharObjectAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public VType put(char key, VType value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - VType previousValue = hasEmptyKey ? (VType) values[mask + 1] : null; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final VType previousValue = (VType) values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return null; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(CharObjectAssociativeContainer container) { - final int count = size(); - for (CharObjectCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (CharObjectCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** {@inheritDoc} */ - @Override - public VType remove(char key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return null; - } - hasEmptyKey = false; - VType previousValue = (VType) values[mask + 1]; - values[mask + 1] = null; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final VType previousValue = (VType) values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return null; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof CharLookupContainer) { - if (hasEmptyKey && other.contains(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = null; - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (CharCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharObjectPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((char) 0), (VType) values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = null; - } - } - - final char[] keys = this.keys; - final VType[] values = (VType[]) this.values; - for (int slot = 0; slot <= mask; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = null; - } - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public VType get(char key) { - if (((key) == 0)) { - return hasEmptyKey ? (VType) values[mask + 1] : null; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return (VType) values[slot]; - } - slot = (slot + 1) & mask; - } - - return null; - } - } - - /** {@inheritDoc} */ - @Override - public VType getOrDefault(char key, VType defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? (VType) values[mask + 1] : defaultValue; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return (VType) values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(char key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(char key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public VType indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return (VType) values[index]; - } - - /** {@inheritDoc} */ - @Override - public VType indexReplace(int index, VType newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - VType previousValue = (VType) values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, char key, VType value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public VType indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - VType previousValue = (VType) values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = null; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((char) 0)); - - Arrays.fill(values, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (CharObjectCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Values are compared - * using {@link Objects#equals(Object)} method. - */ - protected boolean equalElements(CharObjectHashMap other) { - if (other.size() != size()) { - return false; - } - - for (CharObjectCursor c : other) { - char key = c.key; - if (!containsKey(key) || !java.util.Objects.equals(c.value, get(key))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final char[] prevKeys = this.keys; - final VType[] prevValues = (VType[]) this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final CharObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new CharObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharObjectCursor fetch() { - final int mask = CharObjectHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = (VType) values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((char) 0); - cursor.value = (VType) values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final char[] keys = this.keys; - final VType[] values = (VType[]) this.values; - - if (hasEmptyKey) { - procedure.apply(((char) 0), (VType) values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final char[] keys = this.keys; - final VType[] values = (VType[]) this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((char) 0), (VType) values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final CharObjectHashMap owner = CharObjectHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharObjectProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharObjectPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(CharPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final char e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = CharObjectHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((char) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ObjectCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractObjectCollection { - private final CharObjectHashMap owner = CharObjectHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(VType value) { - for (CharObjectCursor c : owner) { - if (java.util.Objects.equals(value, c.value)) { - return true; - } - } - return false; - } - - @Override - public > T forEach(T procedure) { - for (CharObjectCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - for (CharObjectCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator> iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final VType e) { - return owner.removeAll((key, value) -> java.util.Objects.equals(e, value)); - } - - @Override - public int removeAll(final ObjectPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = CharObjectHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = (VType) values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = (VType) values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public CharObjectHashMap clone() { - try { - - CharObjectHashMap cloned = (CharObjectHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (CharObjectCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static CharObjectHashMap from(char[] keys, VType[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - CharObjectHashMap map = new CharObjectHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(char key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(char[] fromKeys, VType[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final char[] keys = this.keys; - final VType[] values = (VType[]) this.values; - final int mask = this.mask; - char existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - char[] prevKeys = this.keys; - VType[] prevValues = (VType[]) this.values; - try { - int emptyElementSlot = 1; - this.keys = (new char[arraySize + emptyElementSlot]); - this.values = ((VType[]) new Object[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, char pendingKey, VType pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final char[] prevKeys = this.keys; - final VType[] prevValues = (VType[]) this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final char[] keys = this.keys; - final VType[] values = (VType[]) this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final char existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((char) 0); - values[gapSlot] = null; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharObjectMap.java b/sources/main/java/com/carrotsearch/hppc/CharObjectMap.java deleted file mode 100644 index 6a1004df..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharObjectMap.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharObjectCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface CharObjectMap extends CharObjectAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public VType get(char key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public VType getOrDefault(char key, VType defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public VType put(char key, VType value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(char key, VType value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(CharObjectAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public VType remove(char key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link CharObjectMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(char key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexReplace(int index, VType newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, char key, VType value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharSet.java b/sources/main/java/com/carrotsearch/hppc/CharSet.java deleted file mode 100644 index a9740eac..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharSet.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** A set of chars. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java") -public interface CharSet extends CharCollection { - /** - * Adds k to the set. - * - * @return Returns true if this element was not part of the set before. Returns - * false if an equal element is already part of the set, does not replace the - * existing element with the argument. - */ - public boolean add(char k); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); - - /** - * Adds all elements from the given {@link CharContainer} to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - * @since 0.9.1 - */ - public int addAll(CharContainer container); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharShortAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/CharShortAssociativeContainer.java deleted file mode 100644 index 66f6c444..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharShortAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see CharContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface CharShortAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(char key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(CharShortPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharShortProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link CharShortPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public CharCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ShortContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharShortHashMap.java b/sources/main/java/com/carrotsearch/hppc/CharShortHashMap.java deleted file mode 100644 index 686281c6..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharShortHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of char to short, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class CharShortHashMap implements CharShortMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public char[] keys; - - /** The array holding values. */ - public short[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public CharShortHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharShortHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public CharShortHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public CharShortHashMap(CharShortAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public short put(char key, short value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - short previousValue = hasEmptyKey ? values[mask + 1] : ((short) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final short previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(CharShortAssociativeContainer container) { - final int count = size(); - for (CharShortCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (CharShortCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public short putOrAdd(char key, short putValue, short incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((short) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public short addTo(char key, short incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public short remove(char key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((short) 0); - } - hasEmptyKey = false; - short previousValue = values[mask + 1]; - values[mask + 1] = ((short) 0); - return previousValue; - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final short previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof CharLookupContainer) { - if (hasEmptyKey && other.contains(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (CharCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharShortPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((char) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - } - - final char[] keys = this.keys; - final short[] values = this.values; - for (int slot = 0; slot <= mask; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(CharPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((char) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - } - - final char[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - char existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public short get(char key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((short) 0); - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public short getOrDefault(char key, short defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(char key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final char[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(char key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final char[] keys = this.keys; - int slot = hashKey(key) & mask; - - char existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public short indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public short indexReplace(int index, short newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - short previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, char key, short value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public short indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - short previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((short) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((char) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (CharShortCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(CharShortHashMap other) { - if (other.size() != size()) { - return false; - } - - for (CharShortCursor c : other) { - char key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final char[] prevKeys = this.keys; - final short[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new CharShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharShortCursor fetch() { - final int mask = CharShortHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((char) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final char[] keys = this.keys; - final short[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((char) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final char[] keys = this.keys; - final short[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((char) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final CharShortHashMap owner = CharShortHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharShortProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharShortPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(CharPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final char e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = CharShortHashMap.this.mask; - while (index <= mask) { - char existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((char) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ShortCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractShortCollection { - private final CharShortHashMap owner = CharShortHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(short value) { - for (CharShortCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (CharShortCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (CharShortCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final short e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final ShortPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = CharShortHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public CharShortHashMap clone() { - try { - - CharShortHashMap cloned = (CharShortHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (CharShortCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static CharShortHashMap from(char[] keys, short[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - CharShortHashMap map = new CharShortHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(char key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(char[] fromKeys, short[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final char[] keys = this.keys; - final short[] values = this.values; - final int mask = this.mask; - char existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - char[] prevKeys = this.keys; - short[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new char[arraySize + emptyElementSlot]); - this.values = (new short[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, char pendingKey, short pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final char[] prevKeys = this.keys; - final short[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final char[] keys = this.keys; - final short[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final char existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((char) 0); - values[gapSlot] = ((short) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharShortMap.java b/sources/main/java/com/carrotsearch/hppc/CharShortMap.java deleted file mode 100644 index e5b0deeb..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharShortMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharShortCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface CharShortMap extends CharShortAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public short get(char key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public short getOrDefault(char key, short defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public short put(char key, short value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(char key, short value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(CharShortAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public short putOrAdd(char key, short putValue, short incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public short addTo(char key, short additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public short remove(char key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link CharShortMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(char key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexReplace(int index, short newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, char key, short value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/CharStack.java b/sources/main/java/com/carrotsearch/hppc/CharStack.java deleted file mode 100644 index fb7a5947..00000000 --- a/sources/main/java/com/carrotsearch/hppc/CharStack.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.CharCursor; - -/** - * A subclass of {@link CharArrayList} adding stack-related utility methods. The top of the stack is - * at the {@link #size()} - 1 element. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") -public class CharStack extends CharArrayList { - /** New instance with sane defaults. */ - public CharStack() { - super(); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public CharStack(int expectedElements) { - super(expectedElements); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public CharStack(int expectedElements, ArraySizingStrategy resizer) { - super(expectedElements, resizer); - } - - /** Create a stack by pushing all elements of another container to it. */ - public CharStack(CharContainer container) { - super(container); - } - - /** Adds one char to the stack. */ - public void push(char e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** Adds two chars to the stack. */ - public void push(char e1, char e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Adds three chars to the stack. */ - public void push(char e1, char e2, char e3) { - ensureBufferSpace(3); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - } - - /** Adds four chars to the stack. */ - public void push(char e1, char e2, char e3, char e4) { - ensureBufferSpace(4); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - buffer[elementsCount++] = e4; - } - - /** Add a range of array elements to the stack. */ - public void push(char[] elements, int start, int len) { - assert start >= 0 && len >= 0; - - ensureBufferSpace(len); - System.arraycopy(elements, start, buffer, elementsCount, len); - elementsCount += len; - } - - /** - * Vararg-signature method for pushing elements at the top of the stack. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void push(char... elements) { - push(elements, 0, elements.length); - } - - /** Pushes all elements from another container to the top of the stack. */ - public int pushAll(CharContainer container) { - return addAll(container); - } - - /** Pushes all elements from another iterable to the top of the stack. */ - public int pushAll(Iterable iterable) { - return addAll(iterable); - } - - /** Discard an arbitrary number of elements from the top of the stack. */ - public void discard(int count) { - assert elementsCount >= count; - - elementsCount -= count; - } - - /** Discard the top element from the stack. */ - public void discard() { - assert elementsCount > 0; - - elementsCount--; - } - - /** Remove the top element from the stack and return it. */ - public char pop() { - return removeLast(); - } - - /** Peek at the top element on the stack. */ - public char peek() { - assert elementsCount > 0; - return buffer[elementsCount - 1]; - } - - /** Create a stack by pushing a variable number of arguments to it. */ - public static CharStack from(char... elements) { - final CharStack stack = new CharStack(elements.length); - stack.push(elements); - return stack; - } - - /** {@inheritDoc} */ - @Override - public CharStack clone() { - return (CharStack) super.clone(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/Containers.java b/sources/main/java/com/carrotsearch/hppc/Containers.java deleted file mode 100644 index edd41b7c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/Containers.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.internals.SuppressForbidden; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Constants used as defaults in containers. - * - * @see HashContainers - */ -public final class Containers { - /** The default number of expected elements for containers. */ - public static final int DEFAULT_EXPECTED_ELEMENTS = 4; - - /** - * External initial seed value. We do not care about multiple assignments so not volatile. - * - * @see #randomSeed64() - */ - private static String testsSeedProperty; - - /** Unique marker for {@link #testsSeedProperty}. */ - private static final String NOT_AVAILABLE = new String(); - - private Containers() {} - - /** - * Provides a (possibly) random initial seed for randomized stuff. - * - *

If tests.seed property is available and accessible, the returned value will be - * derived from the value of that property and will be constant to ensure reproducibility in - * presence of the randomized testing package. - * - * @see "https://github.com/carrotsearch/randomizedtesting" - */ - @SuppressForbidden - public static long randomSeed64() { - if (testsSeedProperty == null) { - testsSeedProperty = System.getProperty("tests.seed", NOT_AVAILABLE); - } - - long initialSeed; - if (testsSeedProperty != NOT_AVAILABLE) { - initialSeed = testsSeedProperty.hashCode(); - } else { - // Mix something that is changing over time (nanoTime) - // ... with something that is thread-local and relatively unique - // even for very short time-spans (new Object's address from a TLAB). - initialSeed = System.nanoTime() ^ System.identityHashCode(new Object()); - } - return BitMixer.mix64(initialSeed); - } - - /** Reset state for tests. */ - static void test$reset() { - testsSeedProperty = null; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/DoubleArrayDeque.java b/sources/main/java/com/carrotsearch/hppc/DoubleArrayDeque.java deleted file mode 100644 index 7561da28..00000000 --- a/sources/main/java/com/carrotsearch/hppc/DoubleArrayDeque.java +++ /dev/null @@ -1,776 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.DoubleCursor; -import com.carrotsearch.hppc.predicates.DoublePredicate; -import com.carrotsearch.hppc.procedures.DoubleProcedure; -import java.util.*; - -/** An array-backed {@link DoubleDeque}. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") -public class DoubleArrayDeque extends AbstractDoubleCollection - implements DoubleDeque, Preallocable, Cloneable, Accountable { - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** Internal array for storing elements of the deque. */ - public double[] buffer = DoubleArrayList.EMPTY_ARRAY; - - /** - * The index of the element at the head of the deque or an arbitrary number equal to tail if the - * deque is empty. - */ - public int head; - - /** The index at which the next element would be added to the tail of the deque. */ - public int tail; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public DoubleArrayDeque() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public DoubleArrayDeque(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public DoubleArrayDeque(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - ensureCapacity(expectedElements); - } - - /** - * Creates a new deque from elements of another container, appending elements at the end of the - * deque in the iteration order. - */ - public DoubleArrayDeque(DoubleContainer container) { - this(container.size()); - addLast(container); - } - - /** {@inheritDoc} */ - @Override - public void addFirst(double e1) { - int h = oneLeft(head, buffer.length); - if (h == tail) { - ensureBufferSpace(1); - h = oneLeft(head, buffer.length); - } - buffer[head = h] = e1; - } - - /** - * Vararg-signature method for adding elements at the front of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to add. - */ - public final void addFirst(double... elements) { - ensureBufferSpace(elements.length); - for (double k : elements) { - addFirst(k); - } - } - - /** - * Inserts all elements from the given container to the front of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(DoubleContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (DoubleCursor cursor : container) { - addFirst(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the front of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(Iterable iterable) { - int size = 0; - for (DoubleCursor cursor : iterable) { - addFirst(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void addLast(double e1) { - int t = oneRight(tail, buffer.length); - if (head == t) { - ensureBufferSpace(1); - t = oneRight(tail, buffer.length); - } - buffer[tail] = e1; - tail = t; - } - - /** - * Vararg-signature method for adding elements at the end of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to iterate over. - */ - public final void addLast(double... elements) { - ensureBufferSpace(1); - for (double k : elements) { - addLast(k); - } - } - - /** - * Inserts all elements from the given container to the end of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(DoubleContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (DoubleCursor cursor : container) { - addLast(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the end of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(Iterable iterable) { - int size = 0; - for (DoubleCursor cursor : iterable) { - addLast(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public double removeFirst() { - assert size() > 0 : "The deque is empty."; - - final double result = buffer[head]; - buffer[head] = 0d; - head = oneRight(head, buffer.length); - return result; - } - - /** {@inheritDoc} */ - @Override - public double removeLast() { - assert size() > 0 : "The deque is empty."; - - tail = oneLeft(tail, buffer.length); - final double result = buffer[tail]; - buffer[tail] = 0d; - return result; - } - - /** {@inheritDoc} */ - @Override - public double getFirst() { - assert size() > 0 : "The deque is empty."; - - return buffer[head]; - } - - /** {@inheritDoc} */ - @Override - public double getLast() { - assert size() > 0 : "The deque is empty."; - - return buffer[oneLeft(tail, buffer.length)]; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(double e1) { - final int index = bufferIndexOf(e1); - if (index >= 0) removeAtBufferIndex(index); - return index; - } - - /** - * Return the index of the first (counting from head) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int bufferIndexOf(double e1) { - final int last = tail; - final int bufLen = buffer.length; - for (int i = head; i != last; i = oneRight(i, bufLen)) { - if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(double e1) { - final int index = lastBufferIndexOf(e1); - if (index >= 0) { - removeAtBufferIndex(index); - } - return index; - } - - /** - * Return the index of the last (counting from tail) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int lastBufferIndexOf(double e1) { - final int bufLen = buffer.length; - final int last = oneLeft(head, bufLen); - for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { - if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) return i; - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(double e1) { - int removed = 0; - final int last = tail; - final int bufLen = buffer.length; - int from, to; - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[from]))) { - buffer[from] = 0d; - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0d; - } - - to = oneRight(to, bufLen); - } - - tail = to; - return removed; - } - - /** - * Removes the element at index in the internal {#link {@link #buffer} array, - * returning its value. - * - * @param index Index of the element to remove. The index must be located between {@link #head} - * and {@link #tail} in modulo {@link #buffer} arithmetic. - */ - public void removeAtBufferIndex(int index) { - assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) - : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; - - // Cache fields in locals (hopefully moved to registers). - final double[] buffer = this.buffer; - final int bufLen = buffer.length; - final int lastIndex = bufLen - 1; - final int head = this.head; - final int tail = this.tail; - - final int leftChunk = Math.abs(index - head) % bufLen; - final int rightChunk = Math.abs(tail - index) % bufLen; - - if (leftChunk < rightChunk) { - if (index >= head) { - System.arraycopy(buffer, head, buffer, head + 1, leftChunk); - } else { - System.arraycopy(buffer, 0, buffer, 1, index); - buffer[0] = buffer[lastIndex]; - System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); - } - buffer[head] = 0d; - this.head = oneRight(head, bufLen); - } else { - if (index < tail) { - System.arraycopy(buffer, index + 1, buffer, index, rightChunk); - } else { - System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); - buffer[lastIndex] = buffer[0]; - System.arraycopy(buffer, 1, buffer, 0, tail); - } - buffer[tail] = 0d; - this.tail = oneLeft(tail, bufLen); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int size() { - if (head <= tail) return tail - head; - else return (tail - head + buffer.length); - } - - /** - * {@inheritDoc} - * - *

The internal array buffers are not released as a result of this call. - * - * @see #release() - */ - @Override - public void clear() { - if (head < tail) { - Arrays.fill(buffer, head, tail, 0d); - } else { - Arrays.fill(buffer, 0, tail, 0d); - Arrays.fill(buffer, head, buffer.length, 0d); - } - this.head = tail = 0; - } - - /** Release internal buffers of this deque and reallocate with the default buffer. */ - public void release() { - this.head = tail = 0; - buffer = DoubleArrayList.EMPTY_ARRAY; - ensureBufferSpace(0); - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - ensureBufferSpace(expectedElements - size()); - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = buffer.length; - final int elementsCount = size(); - - if (elementsCount + expectedAdditions >= bufferLen) { - final int emptySlot = 1; // deque invariant: always an empty slot. - final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); - assert newSize >= (elementsCount + expectedAdditions + emptySlot) - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - try { - final double[] newBuffer = (new double[newSize]); - if (bufferLen > 0) { - toArray(newBuffer); - tail = elementsCount; - head = 0; - } - this.buffer = newBuffer; - } catch (OutOfMemoryError e) { - throw new BufferAllocationException( - "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); - } - } - } - - /** {@inheritDoc} */ - @Override - public double[] toArray() { - - final int size = size(); - return toArray((new double[size])); - } - - /** - * Copies elements of this deque to an array. The content of the target array is - * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). - * - * @param target The target array must be large enough to hold all elements. - * @return Returns the target argument for chaining. - */ - public double[] toArray(double[] target) { - assert target.length >= size() : "Target array must be >= " + size(); - - if (head < tail) { - // The contents is not wrapped around. Just copy. - System.arraycopy(buffer, head, target, 0, size()); - } else if (head > tail) { - // The contents is split. Merge elements from the following indexes: - // [head...buffer.length - 1][0, tail - 1] - final int rightCount = buffer.length - head; - System.arraycopy(buffer, head, target, 0, rightCount); - System.arraycopy(buffer, 0, target, rightCount, tail); - } - - return target; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public DoubleArrayDeque clone() { - try { - - DoubleArrayDeque cloned = (DoubleArrayDeque) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Move one index to the left, wrapping around buffer. */ - protected static int oneLeft(int index, int modulus) { - if (index >= 1) { - return index - 1; - } - return modulus - 1; - } - - /** Move one index to the right, wrapping around buffer. */ - protected static int oneRight(int index, int modulus) { - if (index + 1 == modulus) { - return 0; - } - return index + 1; - } - - @Override - public long ramBytesAllocated() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); - } - - /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ - private final class ValueIterator extends AbstractIterator { - private final DoubleCursor cursor; - private int remaining; - - public ValueIterator() { - cursor = new DoubleCursor(); - cursor.index = oneLeft(head, buffer.length); - this.remaining = size(); - } - - @Override - protected DoubleCursor fetch() { - if (remaining == 0) { - return done(); - } - - remaining--; - cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; - return cursor; - } - } - - /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ - private final class DescendingValueIterator extends AbstractIterator { - private final DoubleCursor cursor; - private int remaining; - - public DescendingValueIterator() { - cursor = new DoubleCursor(); - cursor.index = tail; - this.remaining = size(); - } - - @Override - protected DoubleCursor fetch() { - if (remaining == 0) return done(); - - remaining--; - cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; - return cursor; - } - } - - /** - * Returns a cursor over the values of this deque (in head to tail order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *

-   * for (IntValueCursor c : intDeque) {
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator() { - return new ValueIterator(); - } - - /** - * Returns a cursor over the values of this deque (in tail to head order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *
-   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
-   *   final IntCursor c = i.next();
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator descendingIterator() { - return new DescendingValueIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - forEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, fromIndex, inclusive, to - * toIndex, exclusive. - */ - private void forEach(DoubleProcedure procedure, int fromIndex, final int toIndex) { - final double[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - procedure.apply(buffer[i]); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - int fromIndex = head; - int toIndex = tail; - - final double[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (!predicate.apply(buffer[i])) { - break; - } - } - - return predicate; - } - - /** Applies procedure to all elements of this deque, tail to head. */ - @Override - public T descendingForEach(T procedure) { - descendingForEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive. - */ - private void descendingForEach(DoubleProcedure procedure, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final double[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - procedure.apply(buffer[i]); - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public T descendingForEach(T predicate) { - descendingForEach(predicate, head, tail); - return predicate; - } - - /** - * Applies predicate to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive or until the predicate returns false. - */ - private void descendingForEach(DoublePredicate predicate, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final double[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - if (!predicate.apply(buffer[i])) { - break; - } - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(DoublePredicate predicate) { - final double[] buffer = this.buffer; - final int last = tail; - final int bufLen = buffer.length; - int removed = 0; - int from, to; - from = to = head; - try { - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (predicate.apply(buffer[from])) { - buffer[from] = 0d; - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0d; - } - - to = oneRight(to, bufLen); - } - } finally { - // Keep the deque in consistent state even if the predicate throws an exception. - for (; from != last; from = oneRight(from, bufLen)) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0d; - } - - to = oneRight(to, bufLen); - } - tail = to; - } - - return removed; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(double e) { - int fromIndex = head; - int toIndex = tail; - - final double[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if ((Double.doubleToLongBits(e) == Double.doubleToLongBits(buffer[i]))) { - return true; - } - } - - return false; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1; - int fromIndex = head; - int toIndex = tail; - - final double[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare order-aligned elements against another {@link DoubleDeque}. */ - protected boolean equalElements(DoubleArrayDeque other) { - int max = size(); - if (other.size() != max) { - return false; - } - - Iterator i1 = this.iterator(); - Iterator i2 = other.iterator(); - - while (i1.hasNext() && i2.hasNext()) { - if (!(Double.doubleToLongBits(i1.next().value) == Double.doubleToLongBits(i2.next().value))) { - return false; - } - } - - return !i1.hasNext() && !i2.hasNext(); - } - - /** Create a new deque by pushing a variable number of arguments to the end of it. */ - public static DoubleArrayDeque from(double... elements) { - final DoubleArrayDeque coll = new DoubleArrayDeque(elements.length); - coll.addLast(elements); - return coll; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/DoubleArrayList.java b/sources/main/java/com/carrotsearch/hppc/DoubleArrayList.java deleted file mode 100644 index a0a8bbdd..00000000 --- a/sources/main/java/com/carrotsearch/hppc/DoubleArrayList.java +++ /dev/null @@ -1,586 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.DoublePredicate; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; -import java.util.stream.DoubleStream; - -/** An array-backed list of doubles. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") -public class DoubleArrayList extends AbstractDoubleCollection - implements DoubleIndexedContainer, Preallocable, Cloneable, Accountable { - /** An immutable empty buffer (array). */ - public static final double[] EMPTY_ARRAY = new double[0]; - - ; - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** - * Internal array for storing the list. The array may be larger than the current size ({@link - * #size()}). - */ - public double[] buffer = EMPTY_ARRAY; - - /** Current number of elements stored in {@link #buffer}. */ - public int elementsCount; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public DoubleArrayList() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public DoubleArrayList(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public DoubleArrayList(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - buffer = Arrays.copyOf(buffer, expectedElements); - } - - /** Creates a new list from the elements of another container in its iteration order. */ - public DoubleArrayList(DoubleContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public void add(double e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** - * Appends two elements at the end of the list. To add more than two elements, use add - * (vararg-version) or access the buffer directly (tight loop). - */ - public void add(double e1, double e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Add all elements from a range of given array to the list. */ - public void add(double[] elements, int start, int length) { - assert length >= 0 : "Length must be >= 0"; - - ensureBufferSpace(length); - System.arraycopy(elements, start, buffer, elementsCount, length); - elementsCount += length; - } - - /** - * Vararg-signature method for adding elements at the end of the list. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void add(double... elements) { - add(elements, 0, elements.length); - } - - /** Adds all elements from another container. */ - public int addAll(DoubleContainer container) { - final int size = container.size(); - ensureBufferSpace(size); - - for (DoubleCursor cursor : container) { - add(cursor.value); - } - - return size; - } - - /** Adds all elements from another iterable. */ - public int addAll(Iterable iterable) { - int size = 0; - for (DoubleCursor cursor : iterable) { - add(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void insert(int index, double e1) { - assert (index >= 0 && index <= size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; - - ensureBufferSpace(1); - System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); - buffer[index] = e1; - elementsCount++; - } - - /** {@inheritDoc} */ - @Override - public double get(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - return buffer[index]; - } - - /** {@inheritDoc} */ - @Override - public double set(int index, double e1) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final double v = buffer[index]; - buffer[index] = e1; - return v; - } - - /** {@inheritDoc} */ - @Override - public double removeAt(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final double v = buffer[index]; - System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); - - return v; - } - - /** {@inheritDoc} */ - @Override - public double removeLast() { - assert elementsCount > 0; - - final double v = buffer[--elementsCount]; - - return v; - } - - /** {@inheritDoc} */ - @Override - public void removeRange(int fromIndex, int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); - final int count = toIndex - fromIndex; - elementsCount -= count; - } - - /** {@inheritDoc} */ - @Override - public boolean removeElement(double e1) { - return removeFirst(e1) != -1; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(double e1) { - final int index = indexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(double e1) { - final int index = lastIndexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(double e1) { - int to = 0; - for (int from = 0; from < elementsCount; from++) { - if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[from]))) { - continue; - } - if (to != from) { - buffer[to] = buffer[from]; - } - to++; - } - final int deleted = elementsCount - to; - this.elementsCount = to; - - return deleted; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(double e1) { - return indexOf(e1) >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexOf(double e1) { - for (int i = 0; i < elementsCount; i++) { - if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int lastIndexOf(double e1) { - for (int i = elementsCount - 1; i >= 0; i--) { - if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return elementsCount == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (expectedElements > bufferLen) { - ensureBufferSpace(expectedElements - size()); - } - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (elementsCount + expectedAdditions > bufferLen) { - final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); - assert newSize >= elementsCount + expectedAdditions - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - this.buffer = Arrays.copyOf(buffer, newSize); - } - } - - /** - * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be - * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated - * values will be reset to the default value (zero). If the list is expanded, the elements beyond - * the current size are initialized with JVM-defaults (zero or null values). - */ - public void resize(int newSize) { - if (newSize <= buffer.length) { - if (newSize < elementsCount) { - Arrays.fill(buffer, newSize, elementsCount, 0d); - } else { - Arrays.fill(buffer, elementsCount, newSize, 0d); - } - } else { - ensureCapacity(newSize); - } - this.elementsCount = newSize; - } - - /** {@inheritDoc} */ - @Override - public int size() { - return elementsCount; - } - - /** Trim the internal buffer to the current size. */ - public void trimToSize() { - if (size() != this.buffer.length) { - this.buffer = toArray(); - } - } - - /** - * Sets the number of stored elements to zero. Releases and initializes the internal storage array - * to default values. To clear the list without cleaning the buffer, simply set the {@link - * #elementsCount} field to zero. - */ - @Override - public void clear() { - Arrays.fill(buffer, 0, elementsCount, 0d); - this.elementsCount = 0; - } - - /** Sets the number of stored elements to zero and releases the internal storage array. */ - @Override - public void release() { - this.buffer = EMPTY_ARRAY; - this.elementsCount = 0; - } - - /** - * {@inheritDoc} - * - *

The returned array is sized to match exactly the number of elements of the stack. - */ - @Override - public double[] toArray() { - - return Arrays.copyOf(buffer, elementsCount); - } - - @Override - public DoubleStream stream() { - - return Arrays.stream(buffer, 0, size()); - } - - /** {@inheritDoc} */ - @Override - public DoubleIndexedContainer sort() { - Arrays.sort(buffer, 0, elementsCount); - return this; - } - - /** {@inheritDoc} */ - @Override - public DoubleIndexedContainer reverse() { - for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { - double tmp = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = tmp; - } - return this; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public DoubleArrayList clone() { - try { - - final DoubleArrayList cloned = (DoubleArrayList) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1, max = elementsCount; - for (int i = 0; i < max; i++) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare index-aligned elements against another {@link DoubleIndexedContainer}. */ - protected boolean equalElements(DoubleArrayList other) { - int max = size(); - if (other.size() != max) { - return false; - } - - for (int i = 0; i < max; i++) { - if (!(Double.doubleToLongBits(get(i)) == Double.doubleToLongBits(other.get(i)))) { - return false; - } - } - - return true; - } - - @Override - public long ramBytesAllocated() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); - } - - /** An iterator implementation for {@link DoubleArrayList#iterator}. */ - static final class ValueIterator extends AbstractIterator { - private final DoubleCursor cursor; - - private final double[] buffer; - private final int size; - - public ValueIterator(double[] buffer, int size) { - this.cursor = new DoubleCursor(); - this.cursor.index = -1; - this.size = size; - this.buffer = buffer; - } - - @Override - protected DoubleCursor fetch() { - if (cursor.index + 1 == size) return done(); - - cursor.value = buffer[++cursor.index]; - return cursor; - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new ValueIterator(buffer, size()); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - return forEach(procedure, 0, size()); - } - - /** - * Applies procedure to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive. - */ - public T forEach(T procedure, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final double[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - procedure.apply(buffer[i]); - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(DoublePredicate predicate) { - final double[] buffer = this.buffer; - final int elementsCount = this.elementsCount; - int to = 0; - int from = 0; - try { - for (; from < elementsCount; from++) { - if (predicate.apply(buffer[from])) { - buffer[from] = 0d; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0d; - } - to++; - } - } finally { - // Keep the list in a consistent state, even if the predicate throws an exception. - for (; from < elementsCount; from++) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0d; - } - to++; - } - - this.elementsCount = to; - } - - return elementsCount - to; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - return forEach(predicate, 0, size()); - } - - /** - * Applies predicate to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive, or until predicate returns false. - */ - public T forEach(T predicate, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final double[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - if (!predicate.apply(buffer[i])) break; - } - - return predicate; - } - - /** - * Create a list from a variable number of arguments or an array of double. The - * elements are copied from the argument to the internal buffer. - */ - public static DoubleArrayList from(double... elements) { - final DoubleArrayList list = new DoubleArrayList(elements.length); - list.add(elements); - return list; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/DoubleBufferVisualizer.java b/sources/main/java/com/carrotsearch/hppc/DoubleBufferVisualizer.java deleted file mode 100644 index f708c7a9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/DoubleBufferVisualizer.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Reused buffer visualization routines. - * - * @see DoubleSet#visualizeKeyDistribution(int) - * @see DoubleVTypeMap#visualizeKeyDistribution(int) - */ -class DoubleBufferVisualizer { - static String visualizeKeyDistribution(double[] buffer, int max, int characters) { - final StringBuilder b = new StringBuilder(); - final char[] chars = ".123456789X".toCharArray(); - for (int i = 1, start = -1; i <= characters; i++) { - int end = (int) ((long) i * max / characters); - - if (start + 1 <= end) { - int taken = 0; - int slots = 0; - for (int slot = start + 1; slot <= end; slot++, slots++) { - if (!(Double.doubleToLongBits(buffer[slot]) == 0)) { - taken++; - } - } - b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); - start = end; - } - } - while (b.length() < characters) { - b.append(' '); - } - return b.toString(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/DoubleCollection.java b/sources/main/java/com/carrotsearch/hppc/DoubleCollection.java deleted file mode 100644 index e1c4f96a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/DoubleCollection.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.predicates.DoublePredicate; - -/** - * A collection allows basic, efficient operations on sets of elements (difference and - * intersection). - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") -public interface DoubleCollection extends DoubleContainer { - /** - * Removes all occurrences of e from this collection. - * - * @param e Element to be removed from this collection, if present. - * @return The number of removed elements as a result of this call. - */ - public int removeAll(double e); - - /** - * Removes all elements in this collection that are present in c. - * - * @return Returns the number of removed elements. - */ - public int removeAll(DoubleLookupContainer c); - - /** - * Removes all elements in this collection for which the given predicate returns true - * . - * - * @return Returns the number of removed elements. - */ - public int removeAll(DoublePredicate predicate); - - /** - * Keeps all elements in this collection that are present in c. Runs in time - * proportional to the number of elements in this collection. Equivalent of sets intersection. - * - * @return Returns the number of removed elements. - */ - public int retainAll(DoubleLookupContainer c); - - /** - * Keeps all elements in this collection for which the given predicate returns true. - * - * @return Returns the number of removed elements. - */ - public int retainAll(DoublePredicate predicate); - - /** - * Removes all elements from this collection. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/DoubleContainer.java b/sources/main/java/com/carrotsearch/hppc/DoubleContainer.java deleted file mode 100644 index b5719fd5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/DoubleContainer.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.DoubleCursor; -import com.carrotsearch.hppc.predicates.DoublePredicate; -import com.carrotsearch.hppc.procedures.DoubleProcedure; -import java.util.Iterator; - -/** A generic container holding doubles. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") -public interface DoubleContainer extends Iterable { - /** - * Returns an iterator to a cursor traversing the collection. The order of traversal is not - * defined. More than one cursor may be active at a time. The behavior of iterators is undefined - * if structural changes are made to the underlying collection. - * - *

The iterator is implemented as a cursor and it returns the same cursor instance on - * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current - * list's value (or index in the list) use the cursor's public fields. An example is shown below. - * - *

-   * for (DoubleCursor<double> c : container) {
-   *   System.out.println("index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator(); - - /** - * Lookup a given element in the container. This operation has no speed guarantees (may be linear - * with respect to the size of this container). - * - * @return Returns true if this container has an element equal to e. - */ - public boolean contains(double e); - - /** - * Return the current number of elements in this container. The time for calculating the - * container's size may take O(n) time, although implementing classes should try to - * maintain the current size and return in constant time. - */ - public int size(); - - /** Shortcut for size() == 0. */ - public boolean isEmpty(); - - /** - * Copies all elements of this container to an array. - * - *

The returned array is always a copy, regardless of the storage used by the container. - */ - public double[] toArray(); - - /** - * Applies a procedure to all container elements. Returns the argument (any subclass - * of {@link DoubleProcedure}. This lets the caller to call methods of the argument by chaining - * the call (even if the argument is an anonymous type) to retrieve computed values, for example - * (IntContainer): - * - *

-   * int count = container.forEach(new IntProcedure() {
-   *   int count; // this is a field declaration in an anonymous class.
-   *
-   *   public void apply(int value) {
-   *     count++;
-   *   }
-   * }).count;
-   * 
- */ - public T forEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T forEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/DoubleDeque.java b/sources/main/java/com/carrotsearch/hppc/DoubleDeque.java deleted file mode 100644 index 423026ec..00000000 --- a/sources/main/java/com/carrotsearch/hppc/DoubleDeque.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.DoubleCursor; -import com.carrotsearch.hppc.predicates.DoublePredicate; -import com.carrotsearch.hppc.procedures.DoubleProcedure; -import java.util.Deque; -import java.util.Iterator; - -/** - * A linear collection that supports element insertion and removal at both ends. - * - * @see Deque - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") -public interface DoubleDeque extends DoubleCollection { - /** - * Removes the first element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeFirst(double e); - - /** - * Removes the last element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeLast(double e); - - /** Inserts the specified element at the front of this deque. */ - public void addFirst(double e); - - /** Inserts the specified element at the end of this deque. */ - public void addLast(double e); - - /** - * Retrieves and removes the first element of this deque. - * - * @return the head (first) element of this deque. - */ - public double removeFirst(); - - /** - * Retrieves and removes the last element of this deque. - * - * @return the tail of this deque. - */ - public double removeLast(); - - /** - * Retrieves the first element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public double getFirst(); - - /** - * Retrieves the last element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public double getLast(); - - /** - * @return An iterator over elements in this deque in tail-to-head order. - */ - public Iterator descendingIterator(); - - /** Applies a procedure to all elements in tail-to-head order. */ - public T descendingForEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T descendingForEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/DoubleIndexedContainer.java b/sources/main/java/com/carrotsearch/hppc/DoubleIndexedContainer.java deleted file mode 100644 index faf6b27c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/DoubleIndexedContainer.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.carrotsearch.hppc; - -import java.util.RandomAccess; -import java.util.stream.DoubleStream; - -/** - * An indexed container provides random access to elements based on an index. Indexes - * are zero-based. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeIndexedContainer.java") -public interface DoubleIndexedContainer extends DoubleCollection, RandomAccess { - /** - * Removes the first element that equals e1, returning whether an element has been - * removed. - */ - public boolean removeElement(double e1); - - /** - * Removes the first element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeFirst(double e1); - - /** - * Removes the last element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeLast(double e1); - - /** - * Returns the index of the first occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int indexOf(double e1); - - /** - * Returns the index of the last occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int lastIndexOf(double e1); - - /** Adds an element to the end of this container (the last index is incremented by one). */ - public void add(double e1); - - /** - * Inserts the specified element at the specified position in this list. - * - * @param index The index at which the element should be inserted, shifting any existing and - * subsequent elements to the right. - */ - public void insert(int index, double e1); - - /** - * Replaces the element at the specified position in this list with the specified element. - * - * @return Returns the previous value in the list. - */ - public double set(int index, double e1); - - /** - * @return Returns the element at index index from the list. - */ - public double get(int index); - - /** - * Removes the element at the specified position in this container and returns it. - * - * @see #removeFirst - * @see #removeLast - * @see #removeAll - */ - public double removeAt(int index); - - /** Removes and returns the last element of this container. This container must not be empty. */ - public double removeLast(); - - /** - * Removes from this container all of the elements with indexes between fromIndex, - * inclusive, and toIndex, exclusive. - */ - public void removeRange(int fromIndex, int toIndex); - - /** Returns this container elements as a stream. */ - public DoubleStream stream(); - - /** Sorts the elements in this container and returns this container. */ - public DoubleIndexedContainer sort(); - - /** Reverses the elements in this container and returns this container. */ - public DoubleIndexedContainer reverse(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/DoubleLookupContainer.java b/sources/main/java/com/carrotsearch/hppc/DoubleLookupContainer.java deleted file mode 100644 index c27e6b4b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/DoubleLookupContainer.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Marker interface for containers that can check if they contain a given object in at least time - * O(log n) and ideally in amortized constant time O(1). - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeLookupContainer.java") -public interface DoubleLookupContainer extends DoubleContainer { - public boolean contains(double e); -} diff --git a/sources/main/java/com/carrotsearch/hppc/DoublePgmIndex.java b/sources/main/java/com/carrotsearch/hppc/DoublePgmIndex.java deleted file mode 100644 index ee5ac213..00000000 --- a/sources/main/java/com/carrotsearch/hppc/DoublePgmIndex.java +++ /dev/null @@ -1,600 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.DoubleCursor; -import com.carrotsearch.hppc.procedures.DoubleProcedure; -import java.util.Arrays; -import java.util.Iterator; - -/** - * Space-efficient index that enables fast rank/range search operations on a sorted sequence of - * double. - * - *

Implementation of the PGM-Index described at https://pgm.di.unipi.it/, based on the paper - * - *

- *   Paolo Ferragina and Giorgio Vinciguerra.
- *   The PGM-index: a fully-dynamic compressed learned index with provable worst-case bounds.
- *   PVLDB, 13(8): 1162-1175, 2020.
- * 
- * - * It provides {@code rank} and {@code range} search operations. {@code indexOf()} is faster than - * B+Tree, and the index is much more compact. {@code contains()} is between 4x to 7x slower than - * {@code IntHashSet#contains()}, but between 2.5x to 3x faster than {@link Arrays#binarySearch}. - * - *

Its compactness (40KB for 200MB of keys) makes it efficient for very large collections, the - * index fitting easily in the L2 cache. The {@code epsilon} parameter should be set according to - * the desired space-time trade-off. A smaller value makes the estimation more precise and the range - * smaller but at the cost of increased space usage. In practice, {@code epsilon} 64 is a good sweet - * spot. - * - *

Internally the index uses an optimal piecewise linear mapping from keys to their position in - * the sorted order. This mapping is represented as a sequence of linear models (segments) which are - * themselves recursively indexed by other piecewise linear mappings. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypePgmIndex.java") -public class DoublePgmIndex implements Accountable { - - /** Empty immutable DoublePgmIndex. */ - public static final DoublePgmIndex EMPTY = new DoubleEmptyPgmIndex(); - - /** - * Epsilon approximation range when searching the list of keys. Controls the size of the returned - * search range, strictly greater than 0. It should be set according to the desired space-time - * trade-off. A smaller value makes the estimation more precise and the range smaller but at the - * cost of increased space usage. - * - *

With EPSILON=64 the benchmark with 200MB of keys shows that this PGM index requires only 2% - * additional memory on average (40KB). It depends on the distribution of the keys. This epsilon - * value is good even for 2MB of keys. With EPSILON=32: +5% speed, but 4x space (160KB). - */ - public static final int EPSILON = 64; - - /** - * Epsilon approximation range for the segments layers. Controls the size of the search range in - * the hierarchical segment lists, strictly greater than 0. - */ - public static final int EPSILON_RECURSIVE = 32; - - /** Size of a key, measured in {@link Integer#BYTES} because the key is stored in an int[]. */ - public static final int KEY_SIZE = - RamUsageEstimator.primitiveSizes.get(double.class) / Integer.BYTES; - - /** 2x {@link #KEY_SIZE}. */ - public static final int DOUBLE_KEY_SIZE = KEY_SIZE * 2; - - /** - * Data size of a segment, measured in {@link Integer#BYTES}, because segments are stored in an - * int[]. - */ - public static final int SEGMENT_DATA_SIZE = KEY_SIZE * 3; - - /** Initial value of the exponential jump when scanning out of the epsilon range. */ - public static final int BEYOND_EPSILON_JUMP = 16; - - /** - * The list of keys for which this index is built. It is sorted and may contain duplicate - * elements. - */ - public final DoubleArrayList keys; - - /** The size of the key set. That is, the number of distinct elements in {@link #keys}. */ - public final int size; - - /** The lowest key in {@link #keys}. */ - public final double firstKey; - - /** The highest key in {@link #keys}. */ - public final double lastKey; - - /** The epsilon range used to build this index. */ - public final int epsilon; - - /** The recursive epsilon range used to build this index. */ - public final int epsilonRecursive; - - /** The offsets in {@link #segmentData} of the first segment of each segment level. */ - public final int[] levelOffsets; - - /** The index data. It contains all the segments for all the levels. */ - public final int[] segmentData; - - private DoublePgmIndex( - DoubleArrayList keys, - int size, - int epsilon, - int epsilonRecursive, - int[] levelOffsets, - int[] segmentData) { - assert keys.size() > 0; - assert size > 0 && size <= keys.size(); - assert epsilon > 0; - assert epsilonRecursive > 0; - this.keys = keys; - this.size = size; - firstKey = keys.get(0); - lastKey = keys.get(keys.size() - 1); - this.epsilon = epsilon; - this.epsilonRecursive = epsilonRecursive; - this.levelOffsets = levelOffsets; - this.segmentData = segmentData; - } - - /** Empty set constructor. */ - private DoublePgmIndex() { - keys = new DoubleArrayList(0); - size = 0; - firstKey = 0d; - lastKey = 0d; - epsilon = 0; - epsilonRecursive = 0; - levelOffsets = new int[0]; - segmentData = levelOffsets; - } - - /** Returns the size of the key set. That is, the number of distinct elements in {@link #keys}. */ - public int size() { - return size; - } - - /** Returns whether this key set is empty. */ - public boolean isEmpty() { - return size() == 0; - } - - /** Returns whether this key set contains the given key. */ - public boolean contains(double key) { - return indexOf(key) >= 0; - } - - /** - * Searches the specified key, and returns its index in the element list. If multiple elements are - * equal to the specified key, there is no guarantee which one will be found. - * - * @return The index of the searched key if it is present; otherwise, {@code (-(insertion - * point) - 1)}. The insertion point is defined as the point at which the key would - * be inserted into the list: the index of the first element greater than the key, or {@link - * #keys}#{@code size()} if all the elements are less than the specified key. Note that this - * guarantees that the return value will be >= 0 if and only if the key is found. - */ - public int indexOf(double key) { - if (key < firstKey) { - return -1; - } - if (key > lastKey) { - return -keys.size() - 1; - } - final int[] segmentData = this.segmentData; - int segmentDataIndex = findSegment(key); - int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); - int index = - Math.min( - approximateIndex(key, segmentDataIndex, segmentData), - Math.min(nextIntercept, keys.size() - 1)); - assert index >= 0 && index < keys.size(); - double k = keys.get(index); - if (key < k) { - // Scan sequentially before the approximated index, within epsilon range. - final int fromIndex = Math.max(index - epsilon - 1, 0); - while (--index >= fromIndex) { - k = keys.get(index); - if (key > k) { - return -index - 2; - } - if ((Double.doubleToLongBits(key) == Double.doubleToLongBits(k))) { - return index; - } - } - // Continue scanning out of the epsilon range. - // This might happen in rare cases of precision error during the approximation - // computation for longs (we don't have long double 128 bits in Java). - // This might also happen in rare corner cases of large duplicate elements - // sequence at the epsilon range boundary. - index++; - int jump = BEYOND_EPSILON_JUMP; - do { - int loIndex = Math.max(index - jump, 0); - if (key >= keys.get(loIndex)) { - return Arrays.binarySearch(keys.buffer, loIndex, index, key); - } - index = loIndex; - jump <<= 1; - } while (index > 0); - return -1; - } else if ((Double.doubleToLongBits(key) == Double.doubleToLongBits(k))) { - return index; - } else { - // Scan sequentially after the approximated index, within epsilon range. - final int toIndex = Math.min(index + epsilon + 3, keys.size()); - while (++index < toIndex) { - k = keys.get(index); - if (key < k) { - return -index - 1; - } - if ((Double.doubleToLongBits(key) == Double.doubleToLongBits(k))) { - return index; - } - } - // Continue scanning out of the epsilon range. - int jump = BEYOND_EPSILON_JUMP; - do { - int hiIndex = Math.min(index + jump, keys.size()); - if (key <= keys.get(hiIndex)) { - return Arrays.binarySearch(keys.buffer, index, hiIndex, key); - } - index = hiIndex; - jump <<= 1; - } while (index < keys.size()); - return -keys.size() - 1; - } - } - - /** - * Returns, for any value {@code x}, the number of keys in the sorted list which are smaller than - * {@code x}. It is equal to {@link #indexOf} if {@code x} belongs to the list, or -{@link - * #indexOf}-1 otherwise. - * - *

If multiple elements are equal to the specified key, there is no guarantee which one will be - * found. - * - * @return The index of the searched key if it is present; otherwise, the {@code insertion point}. - * The insertion point is defined as the point at which the key would be inserted into - * the list: the index of the first element greater than the key, or {@link #keys}#{@code - * size()} if all the elements are less than the specified key. Note that this method always - * returns a value >= 0. - */ - public int rank(double x) { - int index = indexOf(x); - return index >= 0 ? index : -index - 1; - } - - /** - * Returns the number of keys in the list that are greater than or equal to {@code minKey} - * (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public int rangeCardinality(double minKey, double maxKey) { - int fromIndex = rank(minKey); - int maxIndex = indexOf(maxKey); - int toIndex = maxIndex >= 0 ? maxIndex + 1 : -maxIndex - 1; - return Math.max(toIndex - fromIndex, 0); - } - - /** - * Returns an iterator over the keys in the list that are greater than or equal to {@code minKey} - * (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public Iterator rangeIterator(double minKey, double maxKey) { - int fromIndex = rank(minKey); - return new RangeIterator(keys, fromIndex, maxKey); - } - - /** - * Applies {@code procedure} to the keys in the list that are greater than or equal to {@code - * minKey} (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public T forEachInRange(T procedure, double minKey, double maxKey) { - final double[] buffer = keys.buffer; - double k; - for (int i = rank(minKey), size = keys.size(); i < size && (k = buffer[i]) <= maxKey; i++) { - procedure.apply(k); - } - return procedure; - } - - /** - * Estimates the allocated memory. It does not count the memory for the list of keys, only for the - * index itself. - */ - @Override - public long ramBytesAllocated() { - // int: size, epsilon, epsilonRecursive - // double: firstKey, lastKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 3 * Integer.BYTES - + 2L * KEY_SIZE * Integer.BYTES - // + keys.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(levelOffsets) - + RamUsageEstimator.shallowSizeOfArray(segmentData); - } - - /** - * Estimates the bytes that are actually used. It does not count the memory for the list of keys, - * only for the index itself. - */ - @Override - public long ramBytesUsed() { - // int: size, epsilon, epsilonRecursive - // double: firstKey, lastKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 3 * Integer.BYTES - + 2L * KEY_SIZE * Integer.BYTES - // + keys.ramBytesUsed() - + RamUsageEstimator.shallowSizeOfArray(levelOffsets) - + RamUsageEstimator.shallowSizeOfArray(segmentData); - } - - /** - * Finds the segment responsible for a given key, that is, the rightmost segment having its first - * key <= the searched key. - * - * @return the segment data index; or -1 if none. - */ - private int findSegment(double key) { - assert key >= firstKey && key <= lastKey; - final int epsilonRecursive = this.epsilonRecursive; - final int[] levelOffsets = this.levelOffsets; - final int[] segmentData = this.segmentData; - int level = levelOffsets.length - 1; - int segmentDataIndex = levelOffsets[level] * SEGMENT_DATA_SIZE; - while (--level >= 0) { - int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); - int index = Math.min(approximateIndex(key, segmentDataIndex, segmentData), nextIntercept); - assert index >= 0 && index <= levelOffsets[level + 1] - levelOffsets[level] - 1; - int sdIndex = (levelOffsets[level] + index) * SEGMENT_DATA_SIZE; - if (getKey(sdIndex, segmentData) <= key) { - // Scan sequentially segments after the approximated index, within the epsilon range. - final int levelNumSegments = levelOffsets[level + 1] - levelOffsets[level] - 1; - final int toIndex = Math.min(index + epsilonRecursive + 3, levelNumSegments); - while (index++ < toIndex && getKey(sdIndex + SEGMENT_DATA_SIZE, segmentData) <= key) { - sdIndex += SEGMENT_DATA_SIZE; - } - } else { - // Scan sequentially segments before the approximated index, within the epsilon range. - final int fromIndex = Math.max(index - epsilonRecursive - 1, 0); - while (index-- > fromIndex) { - sdIndex -= SEGMENT_DATA_SIZE; - if (getKey(sdIndex, segmentData) <= key) { - break; - } - } - } - segmentDataIndex = sdIndex; - } - assert segmentDataIndex >= 0; - return segmentDataIndex; - } - - private int approximateIndex(double key, int segmentDataIndex, int[] segmentData) { - long intercept = getIntercept(segmentDataIndex, segmentData); - double sKey = getKey(segmentDataIndex, segmentData); - double slope = getSlope(segmentDataIndex, segmentData); - int index = (int) (slope * ((double) key - sKey) + intercept); - return Math.max(index, 0); - } - - private static long getIntercept(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getIntercept(segmentDataIndex, segmentData, KEY_SIZE); - } - - private double getKey(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0d); - } - - private static double getSlope(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getSlope(segmentDataIndex + DOUBLE_KEY_SIZE, segmentData, KEY_SIZE); - } - - /** Empty immutable PGM Index. */ - private static class DoubleEmptyPgmIndex extends DoublePgmIndex { - - private final Iterator emptyIterator = new DoubleEmptyIterator(); - - @Override - public int indexOf(double key) { - return -1; - } - - @Override - public Iterator rangeIterator(double minKey, double maxKey) { - return emptyIterator; - } - - @Override - public T forEachInRange(T procedure, double minKey, double maxKey) { - return procedure; - } - - private static class DoubleEmptyIterator extends AbstractIterator { - @Override - protected DoubleCursor fetch() { - return done(); - } - } - } - - /** Iterator over a range of elements in a sorted array. */ - protected static class RangeIterator extends AbstractIterator { - private final double[] buffer; - private final int size; - private final DoubleCursor cursor; - private final double maxKey; - - /** Range iterator from {@code fromIndex} (inclusive) to {@code maxKey} (inclusive). */ - protected RangeIterator(DoubleArrayList keys, int fromIndex, double maxKey) { - this.buffer = keys.buffer; - this.size = keys.size(); - this.cursor = new DoubleCursor(); - this.cursor.index = fromIndex; - this.maxKey = maxKey; - } - - @Override - protected DoubleCursor fetch() { - if (cursor.index >= size) { - return done(); - } - cursor.value = buffer[cursor.index++]; - if (cursor.value > maxKey) { - cursor.index = size; - return done(); - } - return cursor; - } - } - - /** Builds a {@link DoublePgmIndex} on a provided sorted list of keys. */ - public static class DoubleBuilder implements PlaModel.SegmentConsumer, Accountable { - - protected DoubleArrayList keys; - protected int epsilon = EPSILON; - protected int epsilonRecursive = EPSILON_RECURSIVE; - protected PlaModel plam; - protected int size; - protected IntArrayList segmentData; - protected int numSegments; - - /** Sets the sorted list of keys to build the index for; duplicate elements are allowed. */ - public DoubleBuilder setSortedKeys(DoubleArrayList keys) { - this.keys = keys; - return this; - } - - /** Sets the sorted array of keys to build the index for; duplicate elements are allowed. */ - public DoubleBuilder setSortedKeys(double[] keys, int length) { - DoubleArrayList keyList = new DoubleArrayList(0); - keyList.buffer = keys; - keyList.elementsCount = length; - return setSortedKeys(keyList); - } - - /** Sets the epsilon range to use when learning the segments for the list of keys. */ - public DoubleBuilder setEpsilon(int epsilon) { - if (epsilon <= 0) { - throw new IllegalArgumentException("epsilon must be > 0"); - } - this.epsilon = epsilon; - return this; - } - - /** - * Sets the recursive epsilon range to use when learning the segments for the segment levels. - */ - public DoubleBuilder setEpsilonRecursive(int epsilonRecursive) { - if (epsilonRecursive <= 0) { - throw new IllegalArgumentException("epsilonRecursive must be > 0"); - } - this.epsilonRecursive = epsilonRecursive; - return this; - } - - /** Builds the {@link DoublePgmIndex}; or {@link #EMPTY} if there are no keys in the list. */ - public DoublePgmIndex build() { - if (keys == null || keys.size() == 0) { - return (DoublePgmIndex) EMPTY; - } - plam = new PlaModel(epsilon); - - int segmentsInitialCapacity = - Math.min( - Math.max(keys.size() / (2 * epsilon * epsilon) * SEGMENT_DATA_SIZE, 16), 1 << 19); - segmentData = new IntArrayList(segmentsInitialCapacity); - IntArrayList levelOffsets = new IntArrayList(16); - - int levelOffset = 0; - levelOffsets.add(levelOffset); - int levelNumSegments = buildFirstLevel(); - while (levelNumSegments > 1) { - int nextLevelOffset = numSegments; - levelOffsets.add(nextLevelOffset); - levelNumSegments = buildUpperLevel(levelOffset, levelNumSegments); - levelOffset = nextLevelOffset; - } - - int[] segmentDataFinal = segmentData.toArray(); - int[] levelOffsetsFinal = levelOffsets.toArray(); - return new DoublePgmIndex( - keys, size, epsilon, epsilonRecursive, levelOffsetsFinal, segmentDataFinal); - } - - private int buildFirstLevel() { - assert numSegments == 0; - int numKeys = keys.size(); - int size = 0; - double key = keys.get(0); - size++; - plam.addKey(key, 0, this); - for (int i = 1; i < numKeys; i++) { - double nextKey = keys.get(i); - if (!(Double.doubleToLongBits(nextKey) == Double.doubleToLongBits(key))) { - key = nextKey; - plam.addKey(key, i, this); - size++; - } - } - plam.finish(this); - addSentinelSegment(numKeys); - this.size = size; - return numSegments - 1; - } - - private int buildUpperLevel(int levelOffset, int levelNumSegments) { - plam.setEpsilon(epsilonRecursive); - assert numSegments > 0; - int initialNumSegments = numSegments; - int segmentDataIndex = levelOffset * SEGMENT_DATA_SIZE; - double key = getKey(segmentDataIndex, segmentData.buffer); - plam.addKey(key, 0, this); - for (int i = 1; i < levelNumSegments; i++) { - segmentDataIndex += SEGMENT_DATA_SIZE; - double nextKey = getKey(segmentDataIndex, segmentData.buffer); - if (!(Double.doubleToLongBits(nextKey) == Double.doubleToLongBits(key))) { - key = nextKey; - plam.addKey(key, i, this); - } - } - plam.finish(this); - addSentinelSegment(levelNumSegments); - return numSegments - initialNumSegments - 1; - } - - private double getKey(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0d); - } - - /** - * Adds a sentinel segment that is used to give a limit for the position approximation, but does - * not count in the number of segments per level. - */ - private void addSentinelSegment(int endIndex) { - // This sentinel segment is used in findSegment(). - accept(Double.MAX_VALUE, 0d, endIndex); - } - - @Override - public void accept(double firstKey, double slope, long intercept) { - PgmIndexUtil.addIntercept(intercept, segmentData, KEY_SIZE); - PgmIndexUtil.addKey((double) firstKey, segmentData); - PgmIndexUtil.addSlope(slope, segmentData, KEY_SIZE); - numSegments++; - assert segmentData.size() == numSegments * SEGMENT_DATA_SIZE; - } - - /** - * Estimates the allocated memory. It does not count the memory for the list of keys, only for - * the builder itself. - */ - @Override - public long ramBytesAllocated() { - // int: epsilon, epsilonRecursive, size, numSegments - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - // + keys.ramBytesAllocated() - + plam.ramBytesAllocated() - + segmentData.ramBytesAllocated(); - } - - /** - * Estimates the bytes that are actually used. It does not count the memory for the list of - * keys, only for the builder itself. - */ - @Override - public long ramBytesUsed() { - // int: epsilon, epsilonRecursive, size, numSegments - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - // + keys.ramBytesUsed() - + plam.ramBytesUsed() - + segmentData.ramBytesUsed(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/DoubleStack.java b/sources/main/java/com/carrotsearch/hppc/DoubleStack.java deleted file mode 100644 index bf0a2219..00000000 --- a/sources/main/java/com/carrotsearch/hppc/DoubleStack.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.DoubleCursor; - -/** - * A subclass of {@link DoubleArrayList} adding stack-related utility methods. The top of the stack - * is at the {@link #size()} - 1 element. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") -public class DoubleStack extends DoubleArrayList { - /** New instance with sane defaults. */ - public DoubleStack() { - super(); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public DoubleStack(int expectedElements) { - super(expectedElements); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public DoubleStack(int expectedElements, ArraySizingStrategy resizer) { - super(expectedElements, resizer); - } - - /** Create a stack by pushing all elements of another container to it. */ - public DoubleStack(DoubleContainer container) { - super(container); - } - - /** Adds one double to the stack. */ - public void push(double e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** Adds two doubles to the stack. */ - public void push(double e1, double e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Adds three doubles to the stack. */ - public void push(double e1, double e2, double e3) { - ensureBufferSpace(3); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - } - - /** Adds four doubles to the stack. */ - public void push(double e1, double e2, double e3, double e4) { - ensureBufferSpace(4); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - buffer[elementsCount++] = e4; - } - - /** Add a range of array elements to the stack. */ - public void push(double[] elements, int start, int len) { - assert start >= 0 && len >= 0; - - ensureBufferSpace(len); - System.arraycopy(elements, start, buffer, elementsCount, len); - elementsCount += len; - } - - /** - * Vararg-signature method for pushing elements at the top of the stack. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void push(double... elements) { - push(elements, 0, elements.length); - } - - /** Pushes all elements from another container to the top of the stack. */ - public int pushAll(DoubleContainer container) { - return addAll(container); - } - - /** Pushes all elements from another iterable to the top of the stack. */ - public int pushAll(Iterable iterable) { - return addAll(iterable); - } - - /** Discard an arbitrary number of elements from the top of the stack. */ - public void discard(int count) { - assert elementsCount >= count; - - elementsCount -= count; - } - - /** Discard the top element from the stack. */ - public void discard() { - assert elementsCount > 0; - - elementsCount--; - } - - /** Remove the top element from the stack and return it. */ - public double pop() { - return removeLast(); - } - - /** Peek at the top element on the stack. */ - public double peek() { - assert elementsCount > 0; - return buffer[elementsCount - 1]; - } - - /** Create a stack by pushing a variable number of arguments to it. */ - public static DoubleStack from(double... elements) { - final DoubleStack stack = new DoubleStack(elements.length); - stack.push(elements); - return stack; - } - - /** {@inheritDoc} */ - @Override - public DoubleStack clone() { - return (DoubleStack) super.clone(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/FloatArrayDeque.java b/sources/main/java/com/carrotsearch/hppc/FloatArrayDeque.java deleted file mode 100644 index e3d29082..00000000 --- a/sources/main/java/com/carrotsearch/hppc/FloatArrayDeque.java +++ /dev/null @@ -1,776 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.FloatCursor; -import com.carrotsearch.hppc.predicates.FloatPredicate; -import com.carrotsearch.hppc.procedures.FloatProcedure; -import java.util.*; - -/** An array-backed {@link FloatDeque}. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") -public class FloatArrayDeque extends AbstractFloatCollection - implements FloatDeque, Preallocable, Cloneable, Accountable { - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** Internal array for storing elements of the deque. */ - public float[] buffer = FloatArrayList.EMPTY_ARRAY; - - /** - * The index of the element at the head of the deque or an arbitrary number equal to tail if the - * deque is empty. - */ - public int head; - - /** The index at which the next element would be added to the tail of the deque. */ - public int tail; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public FloatArrayDeque() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public FloatArrayDeque(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public FloatArrayDeque(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - ensureCapacity(expectedElements); - } - - /** - * Creates a new deque from elements of another container, appending elements at the end of the - * deque in the iteration order. - */ - public FloatArrayDeque(FloatContainer container) { - this(container.size()); - addLast(container); - } - - /** {@inheritDoc} */ - @Override - public void addFirst(float e1) { - int h = oneLeft(head, buffer.length); - if (h == tail) { - ensureBufferSpace(1); - h = oneLeft(head, buffer.length); - } - buffer[head = h] = e1; - } - - /** - * Vararg-signature method for adding elements at the front of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to add. - */ - public final void addFirst(float... elements) { - ensureBufferSpace(elements.length); - for (float k : elements) { - addFirst(k); - } - } - - /** - * Inserts all elements from the given container to the front of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(FloatContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (FloatCursor cursor : container) { - addFirst(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the front of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(Iterable iterable) { - int size = 0; - for (FloatCursor cursor : iterable) { - addFirst(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void addLast(float e1) { - int t = oneRight(tail, buffer.length); - if (head == t) { - ensureBufferSpace(1); - t = oneRight(tail, buffer.length); - } - buffer[tail] = e1; - tail = t; - } - - /** - * Vararg-signature method for adding elements at the end of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to iterate over. - */ - public final void addLast(float... elements) { - ensureBufferSpace(1); - for (float k : elements) { - addLast(k); - } - } - - /** - * Inserts all elements from the given container to the end of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(FloatContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (FloatCursor cursor : container) { - addLast(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the end of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(Iterable iterable) { - int size = 0; - for (FloatCursor cursor : iterable) { - addLast(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public float removeFirst() { - assert size() > 0 : "The deque is empty."; - - final float result = buffer[head]; - buffer[head] = 0f; - head = oneRight(head, buffer.length); - return result; - } - - /** {@inheritDoc} */ - @Override - public float removeLast() { - assert size() > 0 : "The deque is empty."; - - tail = oneLeft(tail, buffer.length); - final float result = buffer[tail]; - buffer[tail] = 0f; - return result; - } - - /** {@inheritDoc} */ - @Override - public float getFirst() { - assert size() > 0 : "The deque is empty."; - - return buffer[head]; - } - - /** {@inheritDoc} */ - @Override - public float getLast() { - assert size() > 0 : "The deque is empty."; - - return buffer[oneLeft(tail, buffer.length)]; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(float e1) { - final int index = bufferIndexOf(e1); - if (index >= 0) removeAtBufferIndex(index); - return index; - } - - /** - * Return the index of the first (counting from head) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int bufferIndexOf(float e1) { - final int last = tail; - final int bufLen = buffer.length; - for (int i = head; i != last; i = oneRight(i, bufLen)) { - if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(float e1) { - final int index = lastBufferIndexOf(e1); - if (index >= 0) { - removeAtBufferIndex(index); - } - return index; - } - - /** - * Return the index of the last (counting from tail) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int lastBufferIndexOf(float e1) { - final int bufLen = buffer.length; - final int last = oneLeft(head, bufLen); - for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { - if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) return i; - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(float e1) { - int removed = 0; - final int last = tail; - final int bufLen = buffer.length; - int from, to; - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[from]))) { - buffer[from] = 0f; - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0f; - } - - to = oneRight(to, bufLen); - } - - tail = to; - return removed; - } - - /** - * Removes the element at index in the internal {#link {@link #buffer} array, - * returning its value. - * - * @param index Index of the element to remove. The index must be located between {@link #head} - * and {@link #tail} in modulo {@link #buffer} arithmetic. - */ - public void removeAtBufferIndex(int index) { - assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) - : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; - - // Cache fields in locals (hopefully moved to registers). - final float[] buffer = this.buffer; - final int bufLen = buffer.length; - final int lastIndex = bufLen - 1; - final int head = this.head; - final int tail = this.tail; - - final int leftChunk = Math.abs(index - head) % bufLen; - final int rightChunk = Math.abs(tail - index) % bufLen; - - if (leftChunk < rightChunk) { - if (index >= head) { - System.arraycopy(buffer, head, buffer, head + 1, leftChunk); - } else { - System.arraycopy(buffer, 0, buffer, 1, index); - buffer[0] = buffer[lastIndex]; - System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); - } - buffer[head] = 0f; - this.head = oneRight(head, bufLen); - } else { - if (index < tail) { - System.arraycopy(buffer, index + 1, buffer, index, rightChunk); - } else { - System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); - buffer[lastIndex] = buffer[0]; - System.arraycopy(buffer, 1, buffer, 0, tail); - } - buffer[tail] = 0f; - this.tail = oneLeft(tail, bufLen); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int size() { - if (head <= tail) return tail - head; - else return (tail - head + buffer.length); - } - - /** - * {@inheritDoc} - * - *

The internal array buffers are not released as a result of this call. - * - * @see #release() - */ - @Override - public void clear() { - if (head < tail) { - Arrays.fill(buffer, head, tail, 0f); - } else { - Arrays.fill(buffer, 0, tail, 0f); - Arrays.fill(buffer, head, buffer.length, 0f); - } - this.head = tail = 0; - } - - /** Release internal buffers of this deque and reallocate with the default buffer. */ - public void release() { - this.head = tail = 0; - buffer = FloatArrayList.EMPTY_ARRAY; - ensureBufferSpace(0); - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - ensureBufferSpace(expectedElements - size()); - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = buffer.length; - final int elementsCount = size(); - - if (elementsCount + expectedAdditions >= bufferLen) { - final int emptySlot = 1; // deque invariant: always an empty slot. - final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); - assert newSize >= (elementsCount + expectedAdditions + emptySlot) - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - try { - final float[] newBuffer = (new float[newSize]); - if (bufferLen > 0) { - toArray(newBuffer); - tail = elementsCount; - head = 0; - } - this.buffer = newBuffer; - } catch (OutOfMemoryError e) { - throw new BufferAllocationException( - "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); - } - } - } - - /** {@inheritDoc} */ - @Override - public float[] toArray() { - - final int size = size(); - return toArray((new float[size])); - } - - /** - * Copies elements of this deque to an array. The content of the target array is - * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). - * - * @param target The target array must be large enough to hold all elements. - * @return Returns the target argument for chaining. - */ - public float[] toArray(float[] target) { - assert target.length >= size() : "Target array must be >= " + size(); - - if (head < tail) { - // The contents is not wrapped around. Just copy. - System.arraycopy(buffer, head, target, 0, size()); - } else if (head > tail) { - // The contents is split. Merge elements from the following indexes: - // [head...buffer.length - 1][0, tail - 1] - final int rightCount = buffer.length - head; - System.arraycopy(buffer, head, target, 0, rightCount); - System.arraycopy(buffer, 0, target, rightCount, tail); - } - - return target; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public FloatArrayDeque clone() { - try { - - FloatArrayDeque cloned = (FloatArrayDeque) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Move one index to the left, wrapping around buffer. */ - protected static int oneLeft(int index, int modulus) { - if (index >= 1) { - return index - 1; - } - return modulus - 1; - } - - /** Move one index to the right, wrapping around buffer. */ - protected static int oneRight(int index, int modulus) { - if (index + 1 == modulus) { - return 0; - } - return index + 1; - } - - @Override - public long ramBytesAllocated() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); - } - - /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ - private final class ValueIterator extends AbstractIterator { - private final FloatCursor cursor; - private int remaining; - - public ValueIterator() { - cursor = new FloatCursor(); - cursor.index = oneLeft(head, buffer.length); - this.remaining = size(); - } - - @Override - protected FloatCursor fetch() { - if (remaining == 0) { - return done(); - } - - remaining--; - cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; - return cursor; - } - } - - /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ - private final class DescendingValueIterator extends AbstractIterator { - private final FloatCursor cursor; - private int remaining; - - public DescendingValueIterator() { - cursor = new FloatCursor(); - cursor.index = tail; - this.remaining = size(); - } - - @Override - protected FloatCursor fetch() { - if (remaining == 0) return done(); - - remaining--; - cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; - return cursor; - } - } - - /** - * Returns a cursor over the values of this deque (in head to tail order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *

-   * for (IntValueCursor c : intDeque) {
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator() { - return new ValueIterator(); - } - - /** - * Returns a cursor over the values of this deque (in tail to head order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *
-   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
-   *   final IntCursor c = i.next();
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator descendingIterator() { - return new DescendingValueIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - forEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, fromIndex, inclusive, to - * toIndex, exclusive. - */ - private void forEach(FloatProcedure procedure, int fromIndex, final int toIndex) { - final float[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - procedure.apply(buffer[i]); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - int fromIndex = head; - int toIndex = tail; - - final float[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (!predicate.apply(buffer[i])) { - break; - } - } - - return predicate; - } - - /** Applies procedure to all elements of this deque, tail to head. */ - @Override - public T descendingForEach(T procedure) { - descendingForEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive. - */ - private void descendingForEach(FloatProcedure procedure, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final float[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - procedure.apply(buffer[i]); - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public T descendingForEach(T predicate) { - descendingForEach(predicate, head, tail); - return predicate; - } - - /** - * Applies predicate to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive or until the predicate returns false. - */ - private void descendingForEach(FloatPredicate predicate, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final float[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - if (!predicate.apply(buffer[i])) { - break; - } - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(FloatPredicate predicate) { - final float[] buffer = this.buffer; - final int last = tail; - final int bufLen = buffer.length; - int removed = 0; - int from, to; - from = to = head; - try { - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (predicate.apply(buffer[from])) { - buffer[from] = 0f; - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0f; - } - - to = oneRight(to, bufLen); - } - } finally { - // Keep the deque in consistent state even if the predicate throws an exception. - for (; from != last; from = oneRight(from, bufLen)) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0f; - } - - to = oneRight(to, bufLen); - } - tail = to; - } - - return removed; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(float e) { - int fromIndex = head; - int toIndex = tail; - - final float[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if ((Float.floatToIntBits(e) == Float.floatToIntBits(buffer[i]))) { - return true; - } - } - - return false; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1; - int fromIndex = head; - int toIndex = tail; - - final float[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare order-aligned elements against another {@link FloatDeque}. */ - protected boolean equalElements(FloatArrayDeque other) { - int max = size(); - if (other.size() != max) { - return false; - } - - Iterator i1 = this.iterator(); - Iterator i2 = other.iterator(); - - while (i1.hasNext() && i2.hasNext()) { - if (!(Float.floatToIntBits(i1.next().value) == Float.floatToIntBits(i2.next().value))) { - return false; - } - } - - return !i1.hasNext() && !i2.hasNext(); - } - - /** Create a new deque by pushing a variable number of arguments to the end of it. */ - public static FloatArrayDeque from(float... elements) { - final FloatArrayDeque coll = new FloatArrayDeque(elements.length); - coll.addLast(elements); - return coll; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/FloatArrayList.java b/sources/main/java/com/carrotsearch/hppc/FloatArrayList.java deleted file mode 100644 index 0b82dc2a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/FloatArrayList.java +++ /dev/null @@ -1,579 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.FloatPredicate; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** An array-backed list of floats. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") -public class FloatArrayList extends AbstractFloatCollection - implements FloatIndexedContainer, Preallocable, Cloneable, Accountable { - /** An immutable empty buffer (array). */ - public static final float[] EMPTY_ARRAY = new float[0]; - - ; - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** - * Internal array for storing the list. The array may be larger than the current size ({@link - * #size()}). - */ - public float[] buffer = EMPTY_ARRAY; - - /** Current number of elements stored in {@link #buffer}. */ - public int elementsCount; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public FloatArrayList() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public FloatArrayList(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public FloatArrayList(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - buffer = Arrays.copyOf(buffer, expectedElements); - } - - /** Creates a new list from the elements of another container in its iteration order. */ - public FloatArrayList(FloatContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public void add(float e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** - * Appends two elements at the end of the list. To add more than two elements, use add - * (vararg-version) or access the buffer directly (tight loop). - */ - public void add(float e1, float e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Add all elements from a range of given array to the list. */ - public void add(float[] elements, int start, int length) { - assert length >= 0 : "Length must be >= 0"; - - ensureBufferSpace(length); - System.arraycopy(elements, start, buffer, elementsCount, length); - elementsCount += length; - } - - /** - * Vararg-signature method for adding elements at the end of the list. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void add(float... elements) { - add(elements, 0, elements.length); - } - - /** Adds all elements from another container. */ - public int addAll(FloatContainer container) { - final int size = container.size(); - ensureBufferSpace(size); - - for (FloatCursor cursor : container) { - add(cursor.value); - } - - return size; - } - - /** Adds all elements from another iterable. */ - public int addAll(Iterable iterable) { - int size = 0; - for (FloatCursor cursor : iterable) { - add(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void insert(int index, float e1) { - assert (index >= 0 && index <= size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; - - ensureBufferSpace(1); - System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); - buffer[index] = e1; - elementsCount++; - } - - /** {@inheritDoc} */ - @Override - public float get(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - return buffer[index]; - } - - /** {@inheritDoc} */ - @Override - public float set(int index, float e1) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final float v = buffer[index]; - buffer[index] = e1; - return v; - } - - /** {@inheritDoc} */ - @Override - public float removeAt(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final float v = buffer[index]; - System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); - - return v; - } - - /** {@inheritDoc} */ - @Override - public float removeLast() { - assert elementsCount > 0; - - final float v = buffer[--elementsCount]; - - return v; - } - - /** {@inheritDoc} */ - @Override - public void removeRange(int fromIndex, int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); - final int count = toIndex - fromIndex; - elementsCount -= count; - } - - /** {@inheritDoc} */ - @Override - public boolean removeElement(float e1) { - return removeFirst(e1) != -1; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(float e1) { - final int index = indexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(float e1) { - final int index = lastIndexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(float e1) { - int to = 0; - for (int from = 0; from < elementsCount; from++) { - if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[from]))) { - continue; - } - if (to != from) { - buffer[to] = buffer[from]; - } - to++; - } - final int deleted = elementsCount - to; - this.elementsCount = to; - - return deleted; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(float e1) { - return indexOf(e1) >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexOf(float e1) { - for (int i = 0; i < elementsCount; i++) { - if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int lastIndexOf(float e1) { - for (int i = elementsCount - 1; i >= 0; i--) { - if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return elementsCount == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (expectedElements > bufferLen) { - ensureBufferSpace(expectedElements - size()); - } - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (elementsCount + expectedAdditions > bufferLen) { - final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); - assert newSize >= elementsCount + expectedAdditions - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - this.buffer = Arrays.copyOf(buffer, newSize); - } - } - - /** - * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be - * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated - * values will be reset to the default value (zero). If the list is expanded, the elements beyond - * the current size are initialized with JVM-defaults (zero or null values). - */ - public void resize(int newSize) { - if (newSize <= buffer.length) { - if (newSize < elementsCount) { - Arrays.fill(buffer, newSize, elementsCount, 0f); - } else { - Arrays.fill(buffer, elementsCount, newSize, 0f); - } - } else { - ensureCapacity(newSize); - } - this.elementsCount = newSize; - } - - /** {@inheritDoc} */ - @Override - public int size() { - return elementsCount; - } - - /** Trim the internal buffer to the current size. */ - public void trimToSize() { - if (size() != this.buffer.length) { - this.buffer = toArray(); - } - } - - /** - * Sets the number of stored elements to zero. Releases and initializes the internal storage array - * to default values. To clear the list without cleaning the buffer, simply set the {@link - * #elementsCount} field to zero. - */ - @Override - public void clear() { - Arrays.fill(buffer, 0, elementsCount, 0f); - this.elementsCount = 0; - } - - /** Sets the number of stored elements to zero and releases the internal storage array. */ - @Override - public void release() { - this.buffer = EMPTY_ARRAY; - this.elementsCount = 0; - } - - /** - * {@inheritDoc} - * - *

The returned array is sized to match exactly the number of elements of the stack. - */ - @Override - public float[] toArray() { - - return Arrays.copyOf(buffer, elementsCount); - } - - /** {@inheritDoc} */ - @Override - public FloatIndexedContainer sort() { - Arrays.sort(buffer, 0, elementsCount); - return this; - } - - /** {@inheritDoc} */ - @Override - public FloatIndexedContainer reverse() { - for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { - float tmp = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = tmp; - } - return this; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public FloatArrayList clone() { - try { - - final FloatArrayList cloned = (FloatArrayList) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1, max = elementsCount; - for (int i = 0; i < max; i++) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare index-aligned elements against another {@link FloatIndexedContainer}. */ - protected boolean equalElements(FloatArrayList other) { - int max = size(); - if (other.size() != max) { - return false; - } - - for (int i = 0; i < max; i++) { - if (!(Float.floatToIntBits(get(i)) == Float.floatToIntBits(other.get(i)))) { - return false; - } - } - - return true; - } - - @Override - public long ramBytesAllocated() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); - } - - /** An iterator implementation for {@link FloatArrayList#iterator}. */ - static final class ValueIterator extends AbstractIterator { - private final FloatCursor cursor; - - private final float[] buffer; - private final int size; - - public ValueIterator(float[] buffer, int size) { - this.cursor = new FloatCursor(); - this.cursor.index = -1; - this.size = size; - this.buffer = buffer; - } - - @Override - protected FloatCursor fetch() { - if (cursor.index + 1 == size) return done(); - - cursor.value = buffer[++cursor.index]; - return cursor; - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new ValueIterator(buffer, size()); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - return forEach(procedure, 0, size()); - } - - /** - * Applies procedure to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive. - */ - public T forEach(T procedure, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final float[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - procedure.apply(buffer[i]); - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(FloatPredicate predicate) { - final float[] buffer = this.buffer; - final int elementsCount = this.elementsCount; - int to = 0; - int from = 0; - try { - for (; from < elementsCount; from++) { - if (predicate.apply(buffer[from])) { - buffer[from] = 0f; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0f; - } - to++; - } - } finally { - // Keep the list in a consistent state, even if the predicate throws an exception. - for (; from < elementsCount; from++) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0f; - } - to++; - } - - this.elementsCount = to; - } - - return elementsCount - to; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - return forEach(predicate, 0, size()); - } - - /** - * Applies predicate to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive, or until predicate returns false. - */ - public T forEach(T predicate, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final float[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - if (!predicate.apply(buffer[i])) break; - } - - return predicate; - } - - /** - * Create a list from a variable number of arguments or an array of float. The - * elements are copied from the argument to the internal buffer. - */ - public static FloatArrayList from(float... elements) { - final FloatArrayList list = new FloatArrayList(elements.length); - list.add(elements); - return list; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/FloatBufferVisualizer.java b/sources/main/java/com/carrotsearch/hppc/FloatBufferVisualizer.java deleted file mode 100644 index d0c471c3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/FloatBufferVisualizer.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Reused buffer visualization routines. - * - * @see FloatSet#visualizeKeyDistribution(int) - * @see FloatVTypeMap#visualizeKeyDistribution(int) - */ -class FloatBufferVisualizer { - static String visualizeKeyDistribution(float[] buffer, int max, int characters) { - final StringBuilder b = new StringBuilder(); - final char[] chars = ".123456789X".toCharArray(); - for (int i = 1, start = -1; i <= characters; i++) { - int end = (int) ((long) i * max / characters); - - if (start + 1 <= end) { - int taken = 0; - int slots = 0; - for (int slot = start + 1; slot <= end; slot++, slots++) { - if (!(Float.floatToIntBits(buffer[slot]) == 0)) { - taken++; - } - } - b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); - start = end; - } - } - while (b.length() < characters) { - b.append(' '); - } - return b.toString(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/FloatCollection.java b/sources/main/java/com/carrotsearch/hppc/FloatCollection.java deleted file mode 100644 index 491fab8f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/FloatCollection.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.predicates.FloatPredicate; - -/** - * A collection allows basic, efficient operations on sets of elements (difference and - * intersection). - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") -public interface FloatCollection extends FloatContainer { - /** - * Removes all occurrences of e from this collection. - * - * @param e Element to be removed from this collection, if present. - * @return The number of removed elements as a result of this call. - */ - public int removeAll(float e); - - /** - * Removes all elements in this collection that are present in c. - * - * @return Returns the number of removed elements. - */ - public int removeAll(FloatLookupContainer c); - - /** - * Removes all elements in this collection for which the given predicate returns true - * . - * - * @return Returns the number of removed elements. - */ - public int removeAll(FloatPredicate predicate); - - /** - * Keeps all elements in this collection that are present in c. Runs in time - * proportional to the number of elements in this collection. Equivalent of sets intersection. - * - * @return Returns the number of removed elements. - */ - public int retainAll(FloatLookupContainer c); - - /** - * Keeps all elements in this collection for which the given predicate returns true. - * - * @return Returns the number of removed elements. - */ - public int retainAll(FloatPredicate predicate); - - /** - * Removes all elements from this collection. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/FloatContainer.java b/sources/main/java/com/carrotsearch/hppc/FloatContainer.java deleted file mode 100644 index 83b952bf..00000000 --- a/sources/main/java/com/carrotsearch/hppc/FloatContainer.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.FloatCursor; -import com.carrotsearch.hppc.predicates.FloatPredicate; -import com.carrotsearch.hppc.procedures.FloatProcedure; -import java.util.Iterator; - -/** A generic container holding floats. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") -public interface FloatContainer extends Iterable { - /** - * Returns an iterator to a cursor traversing the collection. The order of traversal is not - * defined. More than one cursor may be active at a time. The behavior of iterators is undefined - * if structural changes are made to the underlying collection. - * - *

The iterator is implemented as a cursor and it returns the same cursor instance on - * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current - * list's value (or index in the list) use the cursor's public fields. An example is shown below. - * - *

-   * for (FloatCursor<float> c : container) {
-   *   System.out.println("index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator(); - - /** - * Lookup a given element in the container. This operation has no speed guarantees (may be linear - * with respect to the size of this container). - * - * @return Returns true if this container has an element equal to e. - */ - public boolean contains(float e); - - /** - * Return the current number of elements in this container. The time for calculating the - * container's size may take O(n) time, although implementing classes should try to - * maintain the current size and return in constant time. - */ - public int size(); - - /** Shortcut for size() == 0. */ - public boolean isEmpty(); - - /** - * Copies all elements of this container to an array. - * - *

The returned array is always a copy, regardless of the storage used by the container. - */ - public float[] toArray(); - - /** - * Applies a procedure to all container elements. Returns the argument (any subclass - * of {@link FloatProcedure}. This lets the caller to call methods of the argument by chaining the - * call (even if the argument is an anonymous type) to retrieve computed values, for example - * (IntContainer): - * - *

-   * int count = container.forEach(new IntProcedure() {
-   *   int count; // this is a field declaration in an anonymous class.
-   *
-   *   public void apply(int value) {
-   *     count++;
-   *   }
-   * }).count;
-   * 
- */ - public T forEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T forEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/FloatDeque.java b/sources/main/java/com/carrotsearch/hppc/FloatDeque.java deleted file mode 100644 index 240f3298..00000000 --- a/sources/main/java/com/carrotsearch/hppc/FloatDeque.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.FloatCursor; -import com.carrotsearch.hppc.predicates.FloatPredicate; -import com.carrotsearch.hppc.procedures.FloatProcedure; -import java.util.Deque; -import java.util.Iterator; - -/** - * A linear collection that supports element insertion and removal at both ends. - * - * @see Deque - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") -public interface FloatDeque extends FloatCollection { - /** - * Removes the first element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeFirst(float e); - - /** - * Removes the last element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeLast(float e); - - /** Inserts the specified element at the front of this deque. */ - public void addFirst(float e); - - /** Inserts the specified element at the end of this deque. */ - public void addLast(float e); - - /** - * Retrieves and removes the first element of this deque. - * - * @return the head (first) element of this deque. - */ - public float removeFirst(); - - /** - * Retrieves and removes the last element of this deque. - * - * @return the tail of this deque. - */ - public float removeLast(); - - /** - * Retrieves the first element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public float getFirst(); - - /** - * Retrieves the last element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public float getLast(); - - /** - * @return An iterator over elements in this deque in tail-to-head order. - */ - public Iterator descendingIterator(); - - /** Applies a procedure to all elements in tail-to-head order. */ - public T descendingForEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T descendingForEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/FloatIndexedContainer.java b/sources/main/java/com/carrotsearch/hppc/FloatIndexedContainer.java deleted file mode 100644 index f7beda6a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/FloatIndexedContainer.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.carrotsearch.hppc; - -import java.util.RandomAccess; - -/** - * An indexed container provides random access to elements based on an index. Indexes - * are zero-based. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeIndexedContainer.java") -public interface FloatIndexedContainer extends FloatCollection, RandomAccess { - /** - * Removes the first element that equals e1, returning whether an element has been - * removed. - */ - public boolean removeElement(float e1); - - /** - * Removes the first element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeFirst(float e1); - - /** - * Removes the last element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeLast(float e1); - - /** - * Returns the index of the first occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int indexOf(float e1); - - /** - * Returns the index of the last occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int lastIndexOf(float e1); - - /** Adds an element to the end of this container (the last index is incremented by one). */ - public void add(float e1); - - /** - * Inserts the specified element at the specified position in this list. - * - * @param index The index at which the element should be inserted, shifting any existing and - * subsequent elements to the right. - */ - public void insert(int index, float e1); - - /** - * Replaces the element at the specified position in this list with the specified element. - * - * @return Returns the previous value in the list. - */ - public float set(int index, float e1); - - /** - * @return Returns the element at index index from the list. - */ - public float get(int index); - - /** - * Removes the element at the specified position in this container and returns it. - * - * @see #removeFirst - * @see #removeLast - * @see #removeAll - */ - public float removeAt(int index); - - /** Removes and returns the last element of this container. This container must not be empty. */ - public float removeLast(); - - /** - * Removes from this container all of the elements with indexes between fromIndex, - * inclusive, and toIndex, exclusive. - */ - public void removeRange(int fromIndex, int toIndex); - - /** Returns this container elements as a stream. */ - - /** Sorts the elements in this container and returns this container. */ - public FloatIndexedContainer sort(); - - /** Reverses the elements in this container and returns this container. */ - public FloatIndexedContainer reverse(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/FloatLookupContainer.java b/sources/main/java/com/carrotsearch/hppc/FloatLookupContainer.java deleted file mode 100644 index 558f763b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/FloatLookupContainer.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Marker interface for containers that can check if they contain a given object in at least time - * O(log n) and ideally in amortized constant time O(1). - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeLookupContainer.java") -public interface FloatLookupContainer extends FloatContainer { - public boolean contains(float e); -} diff --git a/sources/main/java/com/carrotsearch/hppc/FloatPgmIndex.java b/sources/main/java/com/carrotsearch/hppc/FloatPgmIndex.java deleted file mode 100644 index e14cb073..00000000 --- a/sources/main/java/com/carrotsearch/hppc/FloatPgmIndex.java +++ /dev/null @@ -1,600 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.FloatCursor; -import com.carrotsearch.hppc.procedures.FloatProcedure; -import java.util.Arrays; -import java.util.Iterator; - -/** - * Space-efficient index that enables fast rank/range search operations on a sorted sequence of - * float. - * - *

Implementation of the PGM-Index described at https://pgm.di.unipi.it/, based on the paper - * - *

- *   Paolo Ferragina and Giorgio Vinciguerra.
- *   The PGM-index: a fully-dynamic compressed learned index with provable worst-case bounds.
- *   PVLDB, 13(8): 1162-1175, 2020.
- * 
- * - * It provides {@code rank} and {@code range} search operations. {@code indexOf()} is faster than - * B+Tree, and the index is much more compact. {@code contains()} is between 4x to 7x slower than - * {@code IntHashSet#contains()}, but between 2.5x to 3x faster than {@link Arrays#binarySearch}. - * - *

Its compactness (40KB for 200MB of keys) makes it efficient for very large collections, the - * index fitting easily in the L2 cache. The {@code epsilon} parameter should be set according to - * the desired space-time trade-off. A smaller value makes the estimation more precise and the range - * smaller but at the cost of increased space usage. In practice, {@code epsilon} 64 is a good sweet - * spot. - * - *

Internally the index uses an optimal piecewise linear mapping from keys to their position in - * the sorted order. This mapping is represented as a sequence of linear models (segments) which are - * themselves recursively indexed by other piecewise linear mappings. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypePgmIndex.java") -public class FloatPgmIndex implements Accountable { - - /** Empty immutable FloatPgmIndex. */ - public static final FloatPgmIndex EMPTY = new FloatEmptyPgmIndex(); - - /** - * Epsilon approximation range when searching the list of keys. Controls the size of the returned - * search range, strictly greater than 0. It should be set according to the desired space-time - * trade-off. A smaller value makes the estimation more precise and the range smaller but at the - * cost of increased space usage. - * - *

With EPSILON=64 the benchmark with 200MB of keys shows that this PGM index requires only 2% - * additional memory on average (40KB). It depends on the distribution of the keys. This epsilon - * value is good even for 2MB of keys. With EPSILON=32: +5% speed, but 4x space (160KB). - */ - public static final int EPSILON = 64; - - /** - * Epsilon approximation range for the segments layers. Controls the size of the search range in - * the hierarchical segment lists, strictly greater than 0. - */ - public static final int EPSILON_RECURSIVE = 32; - - /** Size of a key, measured in {@link Integer#BYTES} because the key is stored in an int[]. */ - public static final int KEY_SIZE = - RamUsageEstimator.primitiveSizes.get(float.class) / Integer.BYTES; - - /** 2x {@link #KEY_SIZE}. */ - public static final int DOUBLE_KEY_SIZE = KEY_SIZE * 2; - - /** - * Data size of a segment, measured in {@link Integer#BYTES}, because segments are stored in an - * int[]. - */ - public static final int SEGMENT_DATA_SIZE = KEY_SIZE * 3; - - /** Initial value of the exponential jump when scanning out of the epsilon range. */ - public static final int BEYOND_EPSILON_JUMP = 16; - - /** - * The list of keys for which this index is built. It is sorted and may contain duplicate - * elements. - */ - public final FloatArrayList keys; - - /** The size of the key set. That is, the number of distinct elements in {@link #keys}. */ - public final int size; - - /** The lowest key in {@link #keys}. */ - public final float firstKey; - - /** The highest key in {@link #keys}. */ - public final float lastKey; - - /** The epsilon range used to build this index. */ - public final int epsilon; - - /** The recursive epsilon range used to build this index. */ - public final int epsilonRecursive; - - /** The offsets in {@link #segmentData} of the first segment of each segment level. */ - public final int[] levelOffsets; - - /** The index data. It contains all the segments for all the levels. */ - public final int[] segmentData; - - private FloatPgmIndex( - FloatArrayList keys, - int size, - int epsilon, - int epsilonRecursive, - int[] levelOffsets, - int[] segmentData) { - assert keys.size() > 0; - assert size > 0 && size <= keys.size(); - assert epsilon > 0; - assert epsilonRecursive > 0; - this.keys = keys; - this.size = size; - firstKey = keys.get(0); - lastKey = keys.get(keys.size() - 1); - this.epsilon = epsilon; - this.epsilonRecursive = epsilonRecursive; - this.levelOffsets = levelOffsets; - this.segmentData = segmentData; - } - - /** Empty set constructor. */ - private FloatPgmIndex() { - keys = new FloatArrayList(0); - size = 0; - firstKey = 0f; - lastKey = 0f; - epsilon = 0; - epsilonRecursive = 0; - levelOffsets = new int[0]; - segmentData = levelOffsets; - } - - /** Returns the size of the key set. That is, the number of distinct elements in {@link #keys}. */ - public int size() { - return size; - } - - /** Returns whether this key set is empty. */ - public boolean isEmpty() { - return size() == 0; - } - - /** Returns whether this key set contains the given key. */ - public boolean contains(float key) { - return indexOf(key) >= 0; - } - - /** - * Searches the specified key, and returns its index in the element list. If multiple elements are - * equal to the specified key, there is no guarantee which one will be found. - * - * @return The index of the searched key if it is present; otherwise, {@code (-(insertion - * point) - 1)}. The insertion point is defined as the point at which the key would - * be inserted into the list: the index of the first element greater than the key, or {@link - * #keys}#{@code size()} if all the elements are less than the specified key. Note that this - * guarantees that the return value will be >= 0 if and only if the key is found. - */ - public int indexOf(float key) { - if (key < firstKey) { - return -1; - } - if (key > lastKey) { - return -keys.size() - 1; - } - final int[] segmentData = this.segmentData; - int segmentDataIndex = findSegment(key); - int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); - int index = - Math.min( - approximateIndex(key, segmentDataIndex, segmentData), - Math.min(nextIntercept, keys.size() - 1)); - assert index >= 0 && index < keys.size(); - float k = keys.get(index); - if (key < k) { - // Scan sequentially before the approximated index, within epsilon range. - final int fromIndex = Math.max(index - epsilon - 1, 0); - while (--index >= fromIndex) { - k = keys.get(index); - if (key > k) { - return -index - 2; - } - if ((Float.floatToIntBits(key) == Float.floatToIntBits(k))) { - return index; - } - } - // Continue scanning out of the epsilon range. - // This might happen in rare cases of precision error during the approximation - // computation for longs (we don't have long double 128 bits in Java). - // This might also happen in rare corner cases of large duplicate elements - // sequence at the epsilon range boundary. - index++; - int jump = BEYOND_EPSILON_JUMP; - do { - int loIndex = Math.max(index - jump, 0); - if (key >= keys.get(loIndex)) { - return Arrays.binarySearch(keys.buffer, loIndex, index, key); - } - index = loIndex; - jump <<= 1; - } while (index > 0); - return -1; - } else if ((Float.floatToIntBits(key) == Float.floatToIntBits(k))) { - return index; - } else { - // Scan sequentially after the approximated index, within epsilon range. - final int toIndex = Math.min(index + epsilon + 3, keys.size()); - while (++index < toIndex) { - k = keys.get(index); - if (key < k) { - return -index - 1; - } - if ((Float.floatToIntBits(key) == Float.floatToIntBits(k))) { - return index; - } - } - // Continue scanning out of the epsilon range. - int jump = BEYOND_EPSILON_JUMP; - do { - int hiIndex = Math.min(index + jump, keys.size()); - if (key <= keys.get(hiIndex)) { - return Arrays.binarySearch(keys.buffer, index, hiIndex, key); - } - index = hiIndex; - jump <<= 1; - } while (index < keys.size()); - return -keys.size() - 1; - } - } - - /** - * Returns, for any value {@code x}, the number of keys in the sorted list which are smaller than - * {@code x}. It is equal to {@link #indexOf} if {@code x} belongs to the list, or -{@link - * #indexOf}-1 otherwise. - * - *

If multiple elements are equal to the specified key, there is no guarantee which one will be - * found. - * - * @return The index of the searched key if it is present; otherwise, the {@code insertion point}. - * The insertion point is defined as the point at which the key would be inserted into - * the list: the index of the first element greater than the key, or {@link #keys}#{@code - * size()} if all the elements are less than the specified key. Note that this method always - * returns a value >= 0. - */ - public int rank(float x) { - int index = indexOf(x); - return index >= 0 ? index : -index - 1; - } - - /** - * Returns the number of keys in the list that are greater than or equal to {@code minKey} - * (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public int rangeCardinality(float minKey, float maxKey) { - int fromIndex = rank(minKey); - int maxIndex = indexOf(maxKey); - int toIndex = maxIndex >= 0 ? maxIndex + 1 : -maxIndex - 1; - return Math.max(toIndex - fromIndex, 0); - } - - /** - * Returns an iterator over the keys in the list that are greater than or equal to {@code minKey} - * (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public Iterator rangeIterator(float minKey, float maxKey) { - int fromIndex = rank(minKey); - return new RangeIterator(keys, fromIndex, maxKey); - } - - /** - * Applies {@code procedure} to the keys in the list that are greater than or equal to {@code - * minKey} (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public T forEachInRange(T procedure, float minKey, float maxKey) { - final float[] buffer = keys.buffer; - float k; - for (int i = rank(minKey), size = keys.size(); i < size && (k = buffer[i]) <= maxKey; i++) { - procedure.apply(k); - } - return procedure; - } - - /** - * Estimates the allocated memory. It does not count the memory for the list of keys, only for the - * index itself. - */ - @Override - public long ramBytesAllocated() { - // int: size, epsilon, epsilonRecursive - // float: firstKey, lastKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 3 * Integer.BYTES - + 2L * KEY_SIZE * Integer.BYTES - // + keys.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(levelOffsets) - + RamUsageEstimator.shallowSizeOfArray(segmentData); - } - - /** - * Estimates the bytes that are actually used. It does not count the memory for the list of keys, - * only for the index itself. - */ - @Override - public long ramBytesUsed() { - // int: size, epsilon, epsilonRecursive - // float: firstKey, lastKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 3 * Integer.BYTES - + 2L * KEY_SIZE * Integer.BYTES - // + keys.ramBytesUsed() - + RamUsageEstimator.shallowSizeOfArray(levelOffsets) - + RamUsageEstimator.shallowSizeOfArray(segmentData); - } - - /** - * Finds the segment responsible for a given key, that is, the rightmost segment having its first - * key <= the searched key. - * - * @return the segment data index; or -1 if none. - */ - private int findSegment(float key) { - assert key >= firstKey && key <= lastKey; - final int epsilonRecursive = this.epsilonRecursive; - final int[] levelOffsets = this.levelOffsets; - final int[] segmentData = this.segmentData; - int level = levelOffsets.length - 1; - int segmentDataIndex = levelOffsets[level] * SEGMENT_DATA_SIZE; - while (--level >= 0) { - int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); - int index = Math.min(approximateIndex(key, segmentDataIndex, segmentData), nextIntercept); - assert index >= 0 && index <= levelOffsets[level + 1] - levelOffsets[level] - 1; - int sdIndex = (levelOffsets[level] + index) * SEGMENT_DATA_SIZE; - if (getKey(sdIndex, segmentData) <= key) { - // Scan sequentially segments after the approximated index, within the epsilon range. - final int levelNumSegments = levelOffsets[level + 1] - levelOffsets[level] - 1; - final int toIndex = Math.min(index + epsilonRecursive + 3, levelNumSegments); - while (index++ < toIndex && getKey(sdIndex + SEGMENT_DATA_SIZE, segmentData) <= key) { - sdIndex += SEGMENT_DATA_SIZE; - } - } else { - // Scan sequentially segments before the approximated index, within the epsilon range. - final int fromIndex = Math.max(index - epsilonRecursive - 1, 0); - while (index-- > fromIndex) { - sdIndex -= SEGMENT_DATA_SIZE; - if (getKey(sdIndex, segmentData) <= key) { - break; - } - } - } - segmentDataIndex = sdIndex; - } - assert segmentDataIndex >= 0; - return segmentDataIndex; - } - - private int approximateIndex(float key, int segmentDataIndex, int[] segmentData) { - long intercept = getIntercept(segmentDataIndex, segmentData); - float sKey = getKey(segmentDataIndex, segmentData); - double slope = getSlope(segmentDataIndex, segmentData); - int index = (int) (slope * ((double) key - sKey) + intercept); - return Math.max(index, 0); - } - - private static long getIntercept(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getIntercept(segmentDataIndex, segmentData, KEY_SIZE); - } - - private float getKey(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0f); - } - - private static double getSlope(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getSlope(segmentDataIndex + DOUBLE_KEY_SIZE, segmentData, KEY_SIZE); - } - - /** Empty immutable PGM Index. */ - private static class FloatEmptyPgmIndex extends FloatPgmIndex { - - private final Iterator emptyIterator = new FloatEmptyIterator(); - - @Override - public int indexOf(float key) { - return -1; - } - - @Override - public Iterator rangeIterator(float minKey, float maxKey) { - return emptyIterator; - } - - @Override - public T forEachInRange(T procedure, float minKey, float maxKey) { - return procedure; - } - - private static class FloatEmptyIterator extends AbstractIterator { - @Override - protected FloatCursor fetch() { - return done(); - } - } - } - - /** Iterator over a range of elements in a sorted array. */ - protected static class RangeIterator extends AbstractIterator { - private final float[] buffer; - private final int size; - private final FloatCursor cursor; - private final float maxKey; - - /** Range iterator from {@code fromIndex} (inclusive) to {@code maxKey} (inclusive). */ - protected RangeIterator(FloatArrayList keys, int fromIndex, float maxKey) { - this.buffer = keys.buffer; - this.size = keys.size(); - this.cursor = new FloatCursor(); - this.cursor.index = fromIndex; - this.maxKey = maxKey; - } - - @Override - protected FloatCursor fetch() { - if (cursor.index >= size) { - return done(); - } - cursor.value = buffer[cursor.index++]; - if (cursor.value > maxKey) { - cursor.index = size; - return done(); - } - return cursor; - } - } - - /** Builds a {@link FloatPgmIndex} on a provided sorted list of keys. */ - public static class FloatBuilder implements PlaModel.SegmentConsumer, Accountable { - - protected FloatArrayList keys; - protected int epsilon = EPSILON; - protected int epsilonRecursive = EPSILON_RECURSIVE; - protected PlaModel plam; - protected int size; - protected IntArrayList segmentData; - protected int numSegments; - - /** Sets the sorted list of keys to build the index for; duplicate elements are allowed. */ - public FloatBuilder setSortedKeys(FloatArrayList keys) { - this.keys = keys; - return this; - } - - /** Sets the sorted array of keys to build the index for; duplicate elements are allowed. */ - public FloatBuilder setSortedKeys(float[] keys, int length) { - FloatArrayList keyList = new FloatArrayList(0); - keyList.buffer = keys; - keyList.elementsCount = length; - return setSortedKeys(keyList); - } - - /** Sets the epsilon range to use when learning the segments for the list of keys. */ - public FloatBuilder setEpsilon(int epsilon) { - if (epsilon <= 0) { - throw new IllegalArgumentException("epsilon must be > 0"); - } - this.epsilon = epsilon; - return this; - } - - /** - * Sets the recursive epsilon range to use when learning the segments for the segment levels. - */ - public FloatBuilder setEpsilonRecursive(int epsilonRecursive) { - if (epsilonRecursive <= 0) { - throw new IllegalArgumentException("epsilonRecursive must be > 0"); - } - this.epsilonRecursive = epsilonRecursive; - return this; - } - - /** Builds the {@link FloatPgmIndex}; or {@link #EMPTY} if there are no keys in the list. */ - public FloatPgmIndex build() { - if (keys == null || keys.size() == 0) { - return (FloatPgmIndex) EMPTY; - } - plam = new PlaModel(epsilon); - - int segmentsInitialCapacity = - Math.min( - Math.max(keys.size() / (2 * epsilon * epsilon) * SEGMENT_DATA_SIZE, 16), 1 << 19); - segmentData = new IntArrayList(segmentsInitialCapacity); - IntArrayList levelOffsets = new IntArrayList(16); - - int levelOffset = 0; - levelOffsets.add(levelOffset); - int levelNumSegments = buildFirstLevel(); - while (levelNumSegments > 1) { - int nextLevelOffset = numSegments; - levelOffsets.add(nextLevelOffset); - levelNumSegments = buildUpperLevel(levelOffset, levelNumSegments); - levelOffset = nextLevelOffset; - } - - int[] segmentDataFinal = segmentData.toArray(); - int[] levelOffsetsFinal = levelOffsets.toArray(); - return new FloatPgmIndex( - keys, size, epsilon, epsilonRecursive, levelOffsetsFinal, segmentDataFinal); - } - - private int buildFirstLevel() { - assert numSegments == 0; - int numKeys = keys.size(); - int size = 0; - float key = keys.get(0); - size++; - plam.addKey(key, 0, this); - for (int i = 1; i < numKeys; i++) { - float nextKey = keys.get(i); - if (!(Float.floatToIntBits(nextKey) == Float.floatToIntBits(key))) { - key = nextKey; - plam.addKey(key, i, this); - size++; - } - } - plam.finish(this); - addSentinelSegment(numKeys); - this.size = size; - return numSegments - 1; - } - - private int buildUpperLevel(int levelOffset, int levelNumSegments) { - plam.setEpsilon(epsilonRecursive); - assert numSegments > 0; - int initialNumSegments = numSegments; - int segmentDataIndex = levelOffset * SEGMENT_DATA_SIZE; - float key = getKey(segmentDataIndex, segmentData.buffer); - plam.addKey(key, 0, this); - for (int i = 1; i < levelNumSegments; i++) { - segmentDataIndex += SEGMENT_DATA_SIZE; - float nextKey = getKey(segmentDataIndex, segmentData.buffer); - if (!(Float.floatToIntBits(nextKey) == Float.floatToIntBits(key))) { - key = nextKey; - plam.addKey(key, i, this); - } - } - plam.finish(this); - addSentinelSegment(levelNumSegments); - return numSegments - initialNumSegments - 1; - } - - private float getKey(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0f); - } - - /** - * Adds a sentinel segment that is used to give a limit for the position approximation, but does - * not count in the number of segments per level. - */ - private void addSentinelSegment(int endIndex) { - // This sentinel segment is used in findSegment(). - accept(Double.MAX_VALUE, 0d, endIndex); - } - - @Override - public void accept(double firstKey, double slope, long intercept) { - PgmIndexUtil.addIntercept(intercept, segmentData, KEY_SIZE); - PgmIndexUtil.addKey((float) firstKey, segmentData); - PgmIndexUtil.addSlope(slope, segmentData, KEY_SIZE); - numSegments++; - assert segmentData.size() == numSegments * SEGMENT_DATA_SIZE; - } - - /** - * Estimates the allocated memory. It does not count the memory for the list of keys, only for - * the builder itself. - */ - @Override - public long ramBytesAllocated() { - // int: epsilon, epsilonRecursive, size, numSegments - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - // + keys.ramBytesAllocated() - + plam.ramBytesAllocated() - + segmentData.ramBytesAllocated(); - } - - /** - * Estimates the bytes that are actually used. It does not count the memory for the list of - * keys, only for the builder itself. - */ - @Override - public long ramBytesUsed() { - // int: epsilon, epsilonRecursive, size, numSegments - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - // + keys.ramBytesUsed() - + plam.ramBytesUsed() - + segmentData.ramBytesUsed(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/FloatStack.java b/sources/main/java/com/carrotsearch/hppc/FloatStack.java deleted file mode 100644 index d2377178..00000000 --- a/sources/main/java/com/carrotsearch/hppc/FloatStack.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.FloatCursor; - -/** - * A subclass of {@link FloatArrayList} adding stack-related utility methods. The top of the stack - * is at the {@link #size()} - 1 element. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") -public class FloatStack extends FloatArrayList { - /** New instance with sane defaults. */ - public FloatStack() { - super(); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public FloatStack(int expectedElements) { - super(expectedElements); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public FloatStack(int expectedElements, ArraySizingStrategy resizer) { - super(expectedElements, resizer); - } - - /** Create a stack by pushing all elements of another container to it. */ - public FloatStack(FloatContainer container) { - super(container); - } - - /** Adds one float to the stack. */ - public void push(float e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** Adds two floats to the stack. */ - public void push(float e1, float e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Adds three floats to the stack. */ - public void push(float e1, float e2, float e3) { - ensureBufferSpace(3); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - } - - /** Adds four floats to the stack. */ - public void push(float e1, float e2, float e3, float e4) { - ensureBufferSpace(4); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - buffer[elementsCount++] = e4; - } - - /** Add a range of array elements to the stack. */ - public void push(float[] elements, int start, int len) { - assert start >= 0 && len >= 0; - - ensureBufferSpace(len); - System.arraycopy(elements, start, buffer, elementsCount, len); - elementsCount += len; - } - - /** - * Vararg-signature method for pushing elements at the top of the stack. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void push(float... elements) { - push(elements, 0, elements.length); - } - - /** Pushes all elements from another container to the top of the stack. */ - public int pushAll(FloatContainer container) { - return addAll(container); - } - - /** Pushes all elements from another iterable to the top of the stack. */ - public int pushAll(Iterable iterable) { - return addAll(iterable); - } - - /** Discard an arbitrary number of elements from the top of the stack. */ - public void discard(int count) { - assert elementsCount >= count; - - elementsCount -= count; - } - - /** Discard the top element from the stack. */ - public void discard() { - assert elementsCount > 0; - - elementsCount--; - } - - /** Remove the top element from the stack and return it. */ - public float pop() { - return removeLast(); - } - - /** Peek at the top element on the stack. */ - public float peek() { - assert elementsCount > 0; - return buffer[elementsCount - 1]; - } - - /** Create a stack by pushing a variable number of arguments to it. */ - public static FloatStack from(float... elements) { - final FloatStack stack = new FloatStack(elements.length); - stack.push(elements); - return stack; - } - - /** {@inheritDoc} */ - @Override - public FloatStack clone() { - return (FloatStack) super.clone(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/Generated.java b/sources/main/java/com/carrotsearch/hppc/Generated.java deleted file mode 100644 index dd8c66d2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/Generated.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.*; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -@Documented -@Retention(SOURCE) -@Target({PACKAGE, TYPE, ANNOTATION_TYPE, METHOD, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, PARAMETER}) -public @interface Generated { - /** - * The value element MUST have the name of the code generator. The recommended convention is to - * use the fully qualified name of the code generator. For example: com.acme.generator.CodeGen. - */ - String[] value(); - - /** Date when the source was generated. */ - String date() default ""; - - /** - * A place holder for any comments that the code generator may want to include in the generated - * code. - */ - String comments() default ""; -} diff --git a/sources/main/java/com/carrotsearch/hppc/HashContainers.java b/sources/main/java/com/carrotsearch/hppc/HashContainers.java deleted file mode 100644 index 7f4be809..00000000 --- a/sources/main/java/com/carrotsearch/hppc/HashContainers.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import java.util.concurrent.atomic.AtomicInteger; - -public final class HashContainers { - /** - * Maximum array size for hash containers (power-of-two and still allocable in Java, not a - * negative int). - */ - public static final int MAX_HASH_ARRAY_LENGTH = 0x80000000 >>> 1; - - /** Minimum hash buffer size. */ - public static final int MIN_HASH_ARRAY_LENGTH = 4; - - /** Default load factor. */ - public static final float DEFAULT_LOAD_FACTOR = 0.75f; - - /** Minimal sane load factor (99 empty slots per 100). */ - public static final float MIN_LOAD_FACTOR = 1 / 100.0f; - - /** Maximum sane load factor (1 empty slot per 100). */ - public static final float MAX_LOAD_FACTOR = 99 / 100.0f; - - private static final AtomicInteger ITERATION_SEED = new AtomicInteger(); - - /** - * Compute and return the maximum number of elements (inclusive) that can be stored in a hash - * container for a given load factor. - */ - public static int maxElements(double loadFactor) { - checkLoadFactor(loadFactor, 0, 1); - return expandAtCount(MAX_HASH_ARRAY_LENGTH, loadFactor) - 1; - } - - /** */ - static int minBufferSize(int elements, double loadFactor) { - if (elements < 0) { - throw new IllegalArgumentException("Number of elements must be >= 0: " + elements); - } - - long length = (long) Math.ceil(elements / loadFactor); - if (length == elements) { - length++; - } - length = Math.max(MIN_HASH_ARRAY_LENGTH, BitUtil.nextHighestPowerOfTwo(length)); - - if (length > MAX_HASH_ARRAY_LENGTH) { - throw new BufferAllocationException( - "Maximum array size exceeded for this load factor (elements: %d, load factor: %f)", - elements, loadFactor); - } - - return (int) length; - } - - /** */ - static int nextBufferSize(int arraySize, int elements, double loadFactor) { - assert checkPowerOfTwo(arraySize); - if (arraySize == MAX_HASH_ARRAY_LENGTH) { - throw new BufferAllocationException( - "Maximum array size exceeded for this load factor (elements: %d, load factor: %f)", - elements, loadFactor); - } - - return (int) arraySize << 1; - } - - /** */ - static int expandAtCount(int arraySize, double loadFactor) { - assert checkPowerOfTwo(arraySize); - // Take care of hash container invariant (there has to be at least one empty slot to ensure - // the lookup loop finds either the element or an empty slot). - return Math.min(arraySize - 1, (int) Math.ceil(arraySize * loadFactor)); - } - - /** */ - static void checkLoadFactor( - double loadFactor, double minAllowedInclusive, double maxAllowedInclusive) { - if (loadFactor < minAllowedInclusive || loadFactor > maxAllowedInclusive) { - throw new BufferAllocationException( - "The load factor should be in range [%.2f, %.2f]: %f", - minAllowedInclusive, maxAllowedInclusive, loadFactor); - } - } - - /** */ - static boolean checkPowerOfTwo(int arraySize) { - // These are internals, we can just assert without retrying. - assert arraySize > 1; - assert BitUtil.nextHighestPowerOfTwo(arraySize) == arraySize; - return true; - } - - /** Provides the next hash iteration order seed. It is simply an incrementing atomic counter. */ - static int nextIterationSeed() { - return ITERATION_SEED.incrementAndGet(); - } - - /** Computes a hash iteration order increment based on the provided seed. */ - static int iterationIncrement(int seed) { - return 29 + ((seed & 7) << 1); // Small odd integer. - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntArrayDeque.java b/sources/main/java/com/carrotsearch/hppc/IntArrayDeque.java deleted file mode 100644 index 06983d90..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntArrayDeque.java +++ /dev/null @@ -1,776 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.IntCursor; -import com.carrotsearch.hppc.predicates.IntPredicate; -import com.carrotsearch.hppc.procedures.IntProcedure; -import java.util.*; - -/** An array-backed {@link IntDeque}. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") -public class IntArrayDeque extends AbstractIntCollection - implements IntDeque, Preallocable, Cloneable, Accountable { - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** Internal array for storing elements of the deque. */ - public int[] buffer = IntArrayList.EMPTY_ARRAY; - - /** - * The index of the element at the head of the deque or an arbitrary number equal to tail if the - * deque is empty. - */ - public int head; - - /** The index at which the next element would be added to the tail of the deque. */ - public int tail; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public IntArrayDeque() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntArrayDeque(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public IntArrayDeque(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - ensureCapacity(expectedElements); - } - - /** - * Creates a new deque from elements of another container, appending elements at the end of the - * deque in the iteration order. - */ - public IntArrayDeque(IntContainer container) { - this(container.size()); - addLast(container); - } - - /** {@inheritDoc} */ - @Override - public void addFirst(int e1) { - int h = oneLeft(head, buffer.length); - if (h == tail) { - ensureBufferSpace(1); - h = oneLeft(head, buffer.length); - } - buffer[head = h] = e1; - } - - /** - * Vararg-signature method for adding elements at the front of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to add. - */ - public final void addFirst(int... elements) { - ensureBufferSpace(elements.length); - for (int k : elements) { - addFirst(k); - } - } - - /** - * Inserts all elements from the given container to the front of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(IntContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (IntCursor cursor : container) { - addFirst(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the front of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(Iterable iterable) { - int size = 0; - for (IntCursor cursor : iterable) { - addFirst(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void addLast(int e1) { - int t = oneRight(tail, buffer.length); - if (head == t) { - ensureBufferSpace(1); - t = oneRight(tail, buffer.length); - } - buffer[tail] = e1; - tail = t; - } - - /** - * Vararg-signature method for adding elements at the end of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to iterate over. - */ - public final void addLast(int... elements) { - ensureBufferSpace(1); - for (int k : elements) { - addLast(k); - } - } - - /** - * Inserts all elements from the given container to the end of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(IntContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (IntCursor cursor : container) { - addLast(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the end of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(Iterable iterable) { - int size = 0; - for (IntCursor cursor : iterable) { - addLast(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst() { - assert size() > 0 : "The deque is empty."; - - final int result = buffer[head]; - buffer[head] = 0; - head = oneRight(head, buffer.length); - return result; - } - - /** {@inheritDoc} */ - @Override - public int removeLast() { - assert size() > 0 : "The deque is empty."; - - tail = oneLeft(tail, buffer.length); - final int result = buffer[tail]; - buffer[tail] = 0; - return result; - } - - /** {@inheritDoc} */ - @Override - public int getFirst() { - assert size() > 0 : "The deque is empty."; - - return buffer[head]; - } - - /** {@inheritDoc} */ - @Override - public int getLast() { - assert size() > 0 : "The deque is empty."; - - return buffer[oneLeft(tail, buffer.length)]; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(int e1) { - final int index = bufferIndexOf(e1); - if (index >= 0) removeAtBufferIndex(index); - return index; - } - - /** - * Return the index of the first (counting from head) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int bufferIndexOf(int e1) { - final int last = tail; - final int bufLen = buffer.length; - for (int i = head; i != last; i = oneRight(i, bufLen)) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(int e1) { - final int index = lastBufferIndexOf(e1); - if (index >= 0) { - removeAtBufferIndex(index); - } - return index; - } - - /** - * Return the index of the last (counting from tail) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int lastBufferIndexOf(int e1) { - final int bufLen = buffer.length; - final int last = oneLeft(head, bufLen); - for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { - if (((e1) == (buffer[i]))) return i; - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(int e1) { - int removed = 0; - final int last = tail; - final int bufLen = buffer.length; - int from, to; - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (((e1) == (buffer[from]))) { - buffer[from] = 0; - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0; - } - - to = oneRight(to, bufLen); - } - - tail = to; - return removed; - } - - /** - * Removes the element at index in the internal {#link {@link #buffer} array, - * returning its value. - * - * @param index Index of the element to remove. The index must be located between {@link #head} - * and {@link #tail} in modulo {@link #buffer} arithmetic. - */ - public void removeAtBufferIndex(int index) { - assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) - : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; - - // Cache fields in locals (hopefully moved to registers). - final int[] buffer = this.buffer; - final int bufLen = buffer.length; - final int lastIndex = bufLen - 1; - final int head = this.head; - final int tail = this.tail; - - final int leftChunk = Math.abs(index - head) % bufLen; - final int rightChunk = Math.abs(tail - index) % bufLen; - - if (leftChunk < rightChunk) { - if (index >= head) { - System.arraycopy(buffer, head, buffer, head + 1, leftChunk); - } else { - System.arraycopy(buffer, 0, buffer, 1, index); - buffer[0] = buffer[lastIndex]; - System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); - } - buffer[head] = 0; - this.head = oneRight(head, bufLen); - } else { - if (index < tail) { - System.arraycopy(buffer, index + 1, buffer, index, rightChunk); - } else { - System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); - buffer[lastIndex] = buffer[0]; - System.arraycopy(buffer, 1, buffer, 0, tail); - } - buffer[tail] = 0; - this.tail = oneLeft(tail, bufLen); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int size() { - if (head <= tail) return tail - head; - else return (tail - head + buffer.length); - } - - /** - * {@inheritDoc} - * - *

The internal array buffers are not released as a result of this call. - * - * @see #release() - */ - @Override - public void clear() { - if (head < tail) { - Arrays.fill(buffer, head, tail, 0); - } else { - Arrays.fill(buffer, 0, tail, 0); - Arrays.fill(buffer, head, buffer.length, 0); - } - this.head = tail = 0; - } - - /** Release internal buffers of this deque and reallocate with the default buffer. */ - public void release() { - this.head = tail = 0; - buffer = IntArrayList.EMPTY_ARRAY; - ensureBufferSpace(0); - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - ensureBufferSpace(expectedElements - size()); - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = buffer.length; - final int elementsCount = size(); - - if (elementsCount + expectedAdditions >= bufferLen) { - final int emptySlot = 1; // deque invariant: always an empty slot. - final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); - assert newSize >= (elementsCount + expectedAdditions + emptySlot) - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - try { - final int[] newBuffer = (new int[newSize]); - if (bufferLen > 0) { - toArray(newBuffer); - tail = elementsCount; - head = 0; - } - this.buffer = newBuffer; - } catch (OutOfMemoryError e) { - throw new BufferAllocationException( - "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); - } - } - } - - /** {@inheritDoc} */ - @Override - public int[] toArray() { - - final int size = size(); - return toArray((new int[size])); - } - - /** - * Copies elements of this deque to an array. The content of the target array is - * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). - * - * @param target The target array must be large enough to hold all elements. - * @return Returns the target argument for chaining. - */ - public int[] toArray(int[] target) { - assert target.length >= size() : "Target array must be >= " + size(); - - if (head < tail) { - // The contents is not wrapped around. Just copy. - System.arraycopy(buffer, head, target, 0, size()); - } else if (head > tail) { - // The contents is split. Merge elements from the following indexes: - // [head...buffer.length - 1][0, tail - 1] - final int rightCount = buffer.length - head; - System.arraycopy(buffer, head, target, 0, rightCount); - System.arraycopy(buffer, 0, target, rightCount, tail); - } - - return target; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public IntArrayDeque clone() { - try { - - IntArrayDeque cloned = (IntArrayDeque) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Move one index to the left, wrapping around buffer. */ - protected static int oneLeft(int index, int modulus) { - if (index >= 1) { - return index - 1; - } - return modulus - 1; - } - - /** Move one index to the right, wrapping around buffer. */ - protected static int oneRight(int index, int modulus) { - if (index + 1 == modulus) { - return 0; - } - return index + 1; - } - - @Override - public long ramBytesAllocated() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); - } - - /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ - private final class ValueIterator extends AbstractIterator { - private final IntCursor cursor; - private int remaining; - - public ValueIterator() { - cursor = new IntCursor(); - cursor.index = oneLeft(head, buffer.length); - this.remaining = size(); - } - - @Override - protected IntCursor fetch() { - if (remaining == 0) { - return done(); - } - - remaining--; - cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; - return cursor; - } - } - - /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ - private final class DescendingValueIterator extends AbstractIterator { - private final IntCursor cursor; - private int remaining; - - public DescendingValueIterator() { - cursor = new IntCursor(); - cursor.index = tail; - this.remaining = size(); - } - - @Override - protected IntCursor fetch() { - if (remaining == 0) return done(); - - remaining--; - cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; - return cursor; - } - } - - /** - * Returns a cursor over the values of this deque (in head to tail order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *

-   * for (IntValueCursor c : intDeque) {
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator() { - return new ValueIterator(); - } - - /** - * Returns a cursor over the values of this deque (in tail to head order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *
-   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
-   *   final IntCursor c = i.next();
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator descendingIterator() { - return new DescendingValueIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - forEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, fromIndex, inclusive, to - * toIndex, exclusive. - */ - private void forEach(IntProcedure procedure, int fromIndex, final int toIndex) { - final int[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - procedure.apply(buffer[i]); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - int fromIndex = head; - int toIndex = tail; - - final int[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (!predicate.apply(buffer[i])) { - break; - } - } - - return predicate; - } - - /** Applies procedure to all elements of this deque, tail to head. */ - @Override - public T descendingForEach(T procedure) { - descendingForEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive. - */ - private void descendingForEach(IntProcedure procedure, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final int[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - procedure.apply(buffer[i]); - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public T descendingForEach(T predicate) { - descendingForEach(predicate, head, tail); - return predicate; - } - - /** - * Applies predicate to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive or until the predicate returns false. - */ - private void descendingForEach(IntPredicate predicate, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final int[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - if (!predicate.apply(buffer[i])) { - break; - } - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - final int[] buffer = this.buffer; - final int last = tail; - final int bufLen = buffer.length; - int removed = 0; - int from, to; - from = to = head; - try { - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (predicate.apply(buffer[from])) { - buffer[from] = 0; - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0; - } - - to = oneRight(to, bufLen); - } - } finally { - // Keep the deque in consistent state even if the predicate throws an exception. - for (; from != last; from = oneRight(from, bufLen)) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0; - } - - to = oneRight(to, bufLen); - } - tail = to; - } - - return removed; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(int e) { - int fromIndex = head; - int toIndex = tail; - - final int[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (((e) == (buffer[i]))) { - return true; - } - } - - return false; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1; - int fromIndex = head; - int toIndex = tail; - - final int[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare order-aligned elements against another {@link IntDeque}. */ - protected boolean equalElements(IntArrayDeque other) { - int max = size(); - if (other.size() != max) { - return false; - } - - Iterator i1 = this.iterator(); - Iterator i2 = other.iterator(); - - while (i1.hasNext() && i2.hasNext()) { - if (!((i1.next().value) == (i2.next().value))) { - return false; - } - } - - return !i1.hasNext() && !i2.hasNext(); - } - - /** Create a new deque by pushing a variable number of arguments to the end of it. */ - public static IntArrayDeque from(int... elements) { - final IntArrayDeque coll = new IntArrayDeque(elements.length); - coll.addLast(elements); - return coll; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntArrayList.java b/sources/main/java/com/carrotsearch/hppc/IntArrayList.java deleted file mode 100644 index 6029be09..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntArrayList.java +++ /dev/null @@ -1,586 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.IntPredicate; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; -import java.util.stream.IntStream; - -/** An array-backed list of ints. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") -public class IntArrayList extends AbstractIntCollection - implements IntIndexedContainer, Preallocable, Cloneable, Accountable { - /** An immutable empty buffer (array). */ - public static final int[] EMPTY_ARRAY = new int[0]; - - ; - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** - * Internal array for storing the list. The array may be larger than the current size ({@link - * #size()}). - */ - public int[] buffer = EMPTY_ARRAY; - - /** Current number of elements stored in {@link #buffer}. */ - public int elementsCount; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public IntArrayList() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntArrayList(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public IntArrayList(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - buffer = Arrays.copyOf(buffer, expectedElements); - } - - /** Creates a new list from the elements of another container in its iteration order. */ - public IntArrayList(IntContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public void add(int e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** - * Appends two elements at the end of the list. To add more than two elements, use add - * (vararg-version) or access the buffer directly (tight loop). - */ - public void add(int e1, int e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Add all elements from a range of given array to the list. */ - public void add(int[] elements, int start, int length) { - assert length >= 0 : "Length must be >= 0"; - - ensureBufferSpace(length); - System.arraycopy(elements, start, buffer, elementsCount, length); - elementsCount += length; - } - - /** - * Vararg-signature method for adding elements at the end of the list. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void add(int... elements) { - add(elements, 0, elements.length); - } - - /** Adds all elements from another container. */ - public int addAll(IntContainer container) { - final int size = container.size(); - ensureBufferSpace(size); - - for (IntCursor cursor : container) { - add(cursor.value); - } - - return size; - } - - /** Adds all elements from another iterable. */ - public int addAll(Iterable iterable) { - int size = 0; - for (IntCursor cursor : iterable) { - add(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void insert(int index, int e1) { - assert (index >= 0 && index <= size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; - - ensureBufferSpace(1); - System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); - buffer[index] = e1; - elementsCount++; - } - - /** {@inheritDoc} */ - @Override - public int get(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - return buffer[index]; - } - - /** {@inheritDoc} */ - @Override - public int set(int index, int e1) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final int v = buffer[index]; - buffer[index] = e1; - return v; - } - - /** {@inheritDoc} */ - @Override - public int removeAt(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final int v = buffer[index]; - System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); - - return v; - } - - /** {@inheritDoc} */ - @Override - public int removeLast() { - assert elementsCount > 0; - - final int v = buffer[--elementsCount]; - - return v; - } - - /** {@inheritDoc} */ - @Override - public void removeRange(int fromIndex, int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); - final int count = toIndex - fromIndex; - elementsCount -= count; - } - - /** {@inheritDoc} */ - @Override - public boolean removeElement(int e1) { - return removeFirst(e1) != -1; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(int e1) { - final int index = indexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(int e1) { - final int index = lastIndexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(int e1) { - int to = 0; - for (int from = 0; from < elementsCount; from++) { - if (((e1) == (buffer[from]))) { - continue; - } - if (to != from) { - buffer[to] = buffer[from]; - } - to++; - } - final int deleted = elementsCount - to; - this.elementsCount = to; - - return deleted; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(int e1) { - return indexOf(e1) >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexOf(int e1) { - for (int i = 0; i < elementsCount; i++) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int lastIndexOf(int e1) { - for (int i = elementsCount - 1; i >= 0; i--) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return elementsCount == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (expectedElements > bufferLen) { - ensureBufferSpace(expectedElements - size()); - } - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (elementsCount + expectedAdditions > bufferLen) { - final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); - assert newSize >= elementsCount + expectedAdditions - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - this.buffer = Arrays.copyOf(buffer, newSize); - } - } - - /** - * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be - * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated - * values will be reset to the default value (zero). If the list is expanded, the elements beyond - * the current size are initialized with JVM-defaults (zero or null values). - */ - public void resize(int newSize) { - if (newSize <= buffer.length) { - if (newSize < elementsCount) { - Arrays.fill(buffer, newSize, elementsCount, 0); - } else { - Arrays.fill(buffer, elementsCount, newSize, 0); - } - } else { - ensureCapacity(newSize); - } - this.elementsCount = newSize; - } - - /** {@inheritDoc} */ - @Override - public int size() { - return elementsCount; - } - - /** Trim the internal buffer to the current size. */ - public void trimToSize() { - if (size() != this.buffer.length) { - this.buffer = toArray(); - } - } - - /** - * Sets the number of stored elements to zero. Releases and initializes the internal storage array - * to default values. To clear the list without cleaning the buffer, simply set the {@link - * #elementsCount} field to zero. - */ - @Override - public void clear() { - Arrays.fill(buffer, 0, elementsCount, 0); - this.elementsCount = 0; - } - - /** Sets the number of stored elements to zero and releases the internal storage array. */ - @Override - public void release() { - this.buffer = EMPTY_ARRAY; - this.elementsCount = 0; - } - - /** - * {@inheritDoc} - * - *

The returned array is sized to match exactly the number of elements of the stack. - */ - @Override - public int[] toArray() { - - return Arrays.copyOf(buffer, elementsCount); - } - - @Override - public IntStream stream() { - - return Arrays.stream(buffer, 0, size()); - } - - /** {@inheritDoc} */ - @Override - public IntIndexedContainer sort() { - Arrays.sort(buffer, 0, elementsCount); - return this; - } - - /** {@inheritDoc} */ - @Override - public IntIndexedContainer reverse() { - for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { - int tmp = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = tmp; - } - return this; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public IntArrayList clone() { - try { - - final IntArrayList cloned = (IntArrayList) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1, max = elementsCount; - for (int i = 0; i < max; i++) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare index-aligned elements against another {@link IntIndexedContainer}. */ - protected boolean equalElements(IntArrayList other) { - int max = size(); - if (other.size() != max) { - return false; - } - - for (int i = 0; i < max; i++) { - if (!((get(i)) == (other.get(i)))) { - return false; - } - } - - return true; - } - - @Override - public long ramBytesAllocated() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); - } - - /** An iterator implementation for {@link IntArrayList#iterator}. */ - static final class ValueIterator extends AbstractIterator { - private final IntCursor cursor; - - private final int[] buffer; - private final int size; - - public ValueIterator(int[] buffer, int size) { - this.cursor = new IntCursor(); - this.cursor.index = -1; - this.size = size; - this.buffer = buffer; - } - - @Override - protected IntCursor fetch() { - if (cursor.index + 1 == size) return done(); - - cursor.value = buffer[++cursor.index]; - return cursor; - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new ValueIterator(buffer, size()); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - return forEach(procedure, 0, size()); - } - - /** - * Applies procedure to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive. - */ - public T forEach(T procedure, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final int[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - procedure.apply(buffer[i]); - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - final int[] buffer = this.buffer; - final int elementsCount = this.elementsCount; - int to = 0; - int from = 0; - try { - for (; from < elementsCount; from++) { - if (predicate.apply(buffer[from])) { - buffer[from] = 0; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0; - } - to++; - } - } finally { - // Keep the list in a consistent state, even if the predicate throws an exception. - for (; from < elementsCount; from++) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0; - } - to++; - } - - this.elementsCount = to; - } - - return elementsCount - to; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - return forEach(predicate, 0, size()); - } - - /** - * Applies predicate to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive, or until predicate returns false. - */ - public T forEach(T predicate, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final int[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - if (!predicate.apply(buffer[i])) break; - } - - return predicate; - } - - /** - * Create a list from a variable number of arguments or an array of int. The elements - * are copied from the argument to the internal buffer. - */ - public static IntArrayList from(int... elements) { - final IntArrayList list = new IntArrayList(elements.length); - list.add(elements); - return list; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntBufferVisualizer.java b/sources/main/java/com/carrotsearch/hppc/IntBufferVisualizer.java deleted file mode 100644 index dddbbfc3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntBufferVisualizer.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Reused buffer visualization routines. - * - * @see IntSet#visualizeKeyDistribution(int) - * @see IntVTypeMap#visualizeKeyDistribution(int) - */ -class IntBufferVisualizer { - static String visualizeKeyDistribution(int[] buffer, int max, int characters) { - final StringBuilder b = new StringBuilder(); - final char[] chars = ".123456789X".toCharArray(); - for (int i = 1, start = -1; i <= characters; i++) { - int end = (int) ((long) i * max / characters); - - if (start + 1 <= end) { - int taken = 0; - int slots = 0; - for (int slot = start + 1; slot <= end; slot++, slots++) { - if (!((buffer[slot]) == 0)) { - taken++; - } - } - b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); - start = end; - } - } - while (b.length() < characters) { - b.append(' '); - } - return b.toString(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntByteAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/IntByteAssociativeContainer.java deleted file mode 100644 index 474cc041..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntByteAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see IntContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface IntByteAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(int key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntBytePredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntByteProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntBytePredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public IntCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ByteContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntByteHashMap.java b/sources/main/java/com/carrotsearch/hppc/IntByteHashMap.java deleted file mode 100644 index 2e69d807..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntByteHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of int to byte, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class IntByteHashMap implements IntByteMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public int[] keys; - - /** The array holding values. */ - public byte[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public IntByteHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntByteHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public IntByteHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public IntByteHashMap(IntByteAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public byte put(int key, byte value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - byte previousValue = hasEmptyKey ? values[mask + 1] : ((byte) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final byte previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(IntByteAssociativeContainer container) { - final int count = size(); - for (IntByteCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (IntByteCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public byte putOrAdd(int key, byte putValue, byte incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((byte) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public byte addTo(int key, byte incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public byte remove(int key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((byte) 0); - } - hasEmptyKey = false; - byte previousValue = values[mask + 1]; - values[mask + 1] = ((byte) 0); - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final byte previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof IntLookupContainer) { - if (hasEmptyKey && other.contains(0)) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (IntCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntBytePredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - } - - final int[] keys = this.keys; - final byte[] values = this.values; - for (int slot = 0; slot <= mask; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0)) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public byte get(int key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((byte) 0); - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public byte getOrDefault(int key, byte defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(int key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(int key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public byte indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public byte indexReplace(int index, byte newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - byte previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, int key, byte value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public byte indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - byte previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((byte) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (IntByteCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(IntByteHashMap other) { - if (other.size() != size()) { - return false; - } - - for (IntByteCursor c : other) { - int key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final int[] prevKeys = this.keys; - final byte[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntByteCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new IntByteCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntByteCursor fetch() { - final int mask = IntByteHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final int[] keys = this.keys; - final byte[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final int[] keys = this.keys; - final byte[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final IntByteHashMap owner = IntByteHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntByteProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntBytePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(IntPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final int e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = IntByteHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ByteCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractByteCollection { - private final IntByteHashMap owner = IntByteHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(byte value) { - for (IntByteCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (IntByteCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (IntByteCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final byte e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final BytePredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ByteCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ByteCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ByteCursor fetch() { - final int mask = IntByteHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public IntByteHashMap clone() { - try { - - IntByteHashMap cloned = (IntByteHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (IntByteCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static IntByteHashMap from(int[] keys, byte[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - IntByteHashMap map = new IntByteHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(int key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(int[] fromKeys, byte[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final int[] keys = this.keys; - final byte[] values = this.values; - final int mask = this.mask; - int existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - int[] prevKeys = this.keys; - byte[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new int[arraySize + emptyElementSlot]); - this.values = (new byte[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, int pendingKey, byte pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final int[] prevKeys = this.keys; - final byte[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final int[] keys = this.keys; - final byte[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final int existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0; - values[gapSlot] = ((byte) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntByteMap.java b/sources/main/java/com/carrotsearch/hppc/IntByteMap.java deleted file mode 100644 index 06ce8aa8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntByteMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntByteCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface IntByteMap extends IntByteAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public byte get(int key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public byte getOrDefault(int key, byte defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public byte put(int key, byte value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(int key, byte value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(IntByteAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public byte putOrAdd(int key, byte putValue, byte incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public byte addTo(int key, byte additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public byte remove(int key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link IntByteMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(int key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexReplace(int index, byte newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, int key, byte value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntCharAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/IntCharAssociativeContainer.java deleted file mode 100644 index adf2f6b1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntCharAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see IntContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface IntCharAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(int key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntCharPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntCharProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntCharPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public IntCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public CharContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntCharHashMap.java b/sources/main/java/com/carrotsearch/hppc/IntCharHashMap.java deleted file mode 100644 index f3bc23a9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntCharHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of int to char, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class IntCharHashMap implements IntCharMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public int[] keys; - - /** The array holding values. */ - public char[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public IntCharHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntCharHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public IntCharHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public IntCharHashMap(IntCharAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public char put(int key, char value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - char previousValue = hasEmptyKey ? values[mask + 1] : ((char) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final char previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(IntCharAssociativeContainer container) { - final int count = size(); - for (IntCharCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (IntCharCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public char putOrAdd(int key, char putValue, char incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((char) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public char addTo(int key, char incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public char remove(int key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((char) 0); - } - hasEmptyKey = false; - char previousValue = values[mask + 1]; - values[mask + 1] = ((char) 0); - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final char previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof IntLookupContainer) { - if (hasEmptyKey && other.contains(0)) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (IntCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntCharPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - } - - final int[] keys = this.keys; - final char[] values = this.values; - for (int slot = 0; slot <= mask; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0)) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public char get(int key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((char) 0); - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public char getOrDefault(int key, char defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(int key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(int key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public char indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public char indexReplace(int index, char newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - char previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, int key, char value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public char indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - char previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((char) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (IntCharCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(IntCharHashMap other) { - if (other.size() != size()) { - return false; - } - - for (IntCharCursor c : other) { - int key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final int[] prevKeys = this.keys; - final char[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntCharCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new IntCharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCharCursor fetch() { - final int mask = IntCharHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final int[] keys = this.keys; - final char[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final int[] keys = this.keys; - final char[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final IntCharHashMap owner = IntCharHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntCharProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntCharPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(IntPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final int e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = IntCharHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public CharCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractCharCollection { - private final IntCharHashMap owner = IntCharHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(char value) { - for (IntCharCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (IntCharCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (IntCharCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final char e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final CharPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = IntCharHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public IntCharHashMap clone() { - try { - - IntCharHashMap cloned = (IntCharHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (IntCharCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static IntCharHashMap from(int[] keys, char[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - IntCharHashMap map = new IntCharHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(int key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(int[] fromKeys, char[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final int[] keys = this.keys; - final char[] values = this.values; - final int mask = this.mask; - int existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - int[] prevKeys = this.keys; - char[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new int[arraySize + emptyElementSlot]); - this.values = (new char[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, int pendingKey, char pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final int[] prevKeys = this.keys; - final char[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final int[] keys = this.keys; - final char[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final int existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0; - values[gapSlot] = ((char) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntCharMap.java b/sources/main/java/com/carrotsearch/hppc/IntCharMap.java deleted file mode 100644 index dd06fe44..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntCharMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntCharCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface IntCharMap extends IntCharAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public char get(int key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public char getOrDefault(int key, char defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public char put(int key, char value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(int key, char value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(IntCharAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public char putOrAdd(int key, char putValue, char incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public char addTo(int key, char additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public char remove(int key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link IntCharMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(int key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexReplace(int index, char newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, int key, char value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntCollection.java b/sources/main/java/com/carrotsearch/hppc/IntCollection.java deleted file mode 100644 index 16ae39bf..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntCollection.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.predicates.IntPredicate; - -/** - * A collection allows basic, efficient operations on sets of elements (difference and - * intersection). - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") -public interface IntCollection extends IntContainer { - /** - * Removes all occurrences of e from this collection. - * - * @param e Element to be removed from this collection, if present. - * @return The number of removed elements as a result of this call. - */ - public int removeAll(int e); - - /** - * Removes all elements in this collection that are present in c. - * - * @return Returns the number of removed elements. - */ - public int removeAll(IntLookupContainer c); - - /** - * Removes all elements in this collection for which the given predicate returns true - * . - * - * @return Returns the number of removed elements. - */ - public int removeAll(IntPredicate predicate); - - /** - * Keeps all elements in this collection that are present in c. Runs in time - * proportional to the number of elements in this collection. Equivalent of sets intersection. - * - * @return Returns the number of removed elements. - */ - public int retainAll(IntLookupContainer c); - - /** - * Keeps all elements in this collection for which the given predicate returns true. - * - * @return Returns the number of removed elements. - */ - public int retainAll(IntPredicate predicate); - - /** - * Removes all elements from this collection. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntContainer.java b/sources/main/java/com/carrotsearch/hppc/IntContainer.java deleted file mode 100644 index fd8c1b3a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntContainer.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntCursor; -import com.carrotsearch.hppc.predicates.IntPredicate; -import com.carrotsearch.hppc.procedures.IntProcedure; -import java.util.Iterator; - -/** A generic container holding ints. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") -public interface IntContainer extends Iterable { - /** - * Returns an iterator to a cursor traversing the collection. The order of traversal is not - * defined. More than one cursor may be active at a time. The behavior of iterators is undefined - * if structural changes are made to the underlying collection. - * - *

The iterator is implemented as a cursor and it returns the same cursor instance on - * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current - * list's value (or index in the list) use the cursor's public fields. An example is shown below. - * - *

-   * for (IntCursor<int> c : container) {
-   *   System.out.println("index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator(); - - /** - * Lookup a given element in the container. This operation has no speed guarantees (may be linear - * with respect to the size of this container). - * - * @return Returns true if this container has an element equal to e. - */ - public boolean contains(int e); - - /** - * Return the current number of elements in this container. The time for calculating the - * container's size may take O(n) time, although implementing classes should try to - * maintain the current size and return in constant time. - */ - public int size(); - - /** Shortcut for size() == 0. */ - public boolean isEmpty(); - - /** - * Copies all elements of this container to an array. - * - *

The returned array is always a copy, regardless of the storage used by the container. - */ - public int[] toArray(); - - /** - * Applies a procedure to all container elements. Returns the argument (any subclass - * of {@link IntProcedure}. This lets the caller to call methods of the argument by chaining the - * call (even if the argument is an anonymous type) to retrieve computed values, for example - * (IntContainer): - * - *

-   * int count = container.forEach(new IntProcedure() {
-   *   int count; // this is a field declaration in an anonymous class.
-   *
-   *   public void apply(int value) {
-   *     count++;
-   *   }
-   * }).count;
-   * 
- */ - public T forEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T forEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntDeque.java b/sources/main/java/com/carrotsearch/hppc/IntDeque.java deleted file mode 100644 index e7981ad5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntDeque.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntCursor; -import com.carrotsearch.hppc.predicates.IntPredicate; -import com.carrotsearch.hppc.procedures.IntProcedure; -import java.util.Deque; -import java.util.Iterator; - -/** - * A linear collection that supports element insertion and removal at both ends. - * - * @see Deque - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") -public interface IntDeque extends IntCollection { - /** - * Removes the first element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeFirst(int e); - - /** - * Removes the last element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeLast(int e); - - /** Inserts the specified element at the front of this deque. */ - public void addFirst(int e); - - /** Inserts the specified element at the end of this deque. */ - public void addLast(int e); - - /** - * Retrieves and removes the first element of this deque. - * - * @return the head (first) element of this deque. - */ - public int removeFirst(); - - /** - * Retrieves and removes the last element of this deque. - * - * @return the tail of this deque. - */ - public int removeLast(); - - /** - * Retrieves the first element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public int getFirst(); - - /** - * Retrieves the last element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public int getLast(); - - /** - * @return An iterator over elements in this deque in tail-to-head order. - */ - public Iterator descendingIterator(); - - /** Applies a procedure to all elements in tail-to-head order. */ - public T descendingForEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T descendingForEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntDoubleAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/IntDoubleAssociativeContainer.java deleted file mode 100644 index b447931f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntDoubleAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see IntContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface IntDoubleAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *
-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(int key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntDoublePredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntDoubleProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntDoublePredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public IntCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public DoubleContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntDoubleHashMap.java b/sources/main/java/com/carrotsearch/hppc/IntDoubleHashMap.java deleted file mode 100644 index d070d0f8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntDoubleHashMap.java +++ /dev/null @@ -1,1082 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of int to double, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class IntDoubleHashMap implements IntDoubleMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public int[] keys; - - /** The array holding values. */ - public double[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public IntDoubleHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntDoubleHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public IntDoubleHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public IntDoubleHashMap(IntDoubleAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public double put(int key, double value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - double previousValue = hasEmptyKey ? values[mask + 1] : 0d; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final double previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(IntDoubleAssociativeContainer container) { - final int count = size(); - for (IntDoubleCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (IntDoubleCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public double putOrAdd(int key, double putValue, double incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((double) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public double addTo(int key, double incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public double remove(int key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0d; - } - hasEmptyKey = false; - double previousValue = values[mask + 1]; - values[mask + 1] = 0d; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final double previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof IntLookupContainer) { - if (hasEmptyKey && other.contains(0)) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (IntCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntDoublePredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - } - - final int[] keys = this.keys; - final double[] values = this.values; - for (int slot = 0; slot <= mask; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0)) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public double get(int key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0d; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public double getOrDefault(int key, double defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(int key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(int key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public double indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public double indexReplace(int index, double newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - double previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, int key, double value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public double indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - double previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0d; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (IntDoubleCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(IntDoubleHashMap other) { - if (other.size() != size()) { - return false; - } - - for (IntDoubleCursor c : other) { - int key = c.key; - if (!containsKey(key) - || !(Double.doubleToLongBits(c.value) == Double.doubleToLongBits(get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final int[] prevKeys = this.keys; - final double[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntDoubleCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new IntDoubleCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntDoubleCursor fetch() { - final int mask = IntDoubleHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final int[] keys = this.keys; - final double[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final int[] keys = this.keys; - final double[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final IntDoubleHashMap owner = IntDoubleHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntDoubleProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntDoublePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(IntPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final int e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = IntDoubleHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public DoubleCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractDoubleCollection { - private final IntDoubleHashMap owner = IntDoubleHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(double value) { - for (IntDoubleCursor c : owner) { - if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (IntDoubleCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (IntDoubleCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final double e) { - return owner.removeAll( - (key, value) -> (Double.doubleToLongBits(e) == Double.doubleToLongBits(value))); - } - - @Override - public int removeAll(final DoublePredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final DoubleCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new DoubleCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected DoubleCursor fetch() { - final int mask = IntDoubleHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public IntDoubleHashMap clone() { - try { - - IntDoubleHashMap cloned = (IntDoubleHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (IntDoubleCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static IntDoubleHashMap from(int[] keys, double[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - IntDoubleHashMap map = new IntDoubleHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(int key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(int[] fromKeys, double[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final int[] keys = this.keys; - final double[] values = this.values; - final int mask = this.mask; - int existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - int[] prevKeys = this.keys; - double[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new int[arraySize + emptyElementSlot]); - this.values = (new double[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, int pendingKey, double pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final int[] prevKeys = this.keys; - final double[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final int[] keys = this.keys; - final double[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final int existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0; - values[gapSlot] = 0d; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntDoubleMap.java b/sources/main/java/com/carrotsearch/hppc/IntDoubleMap.java deleted file mode 100644 index 03691ffa..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntDoubleMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntDoubleCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface IntDoubleMap extends IntDoubleAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public double get(int key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public double getOrDefault(int key, double defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public double put(int key, double value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(int key, double value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(IntDoubleAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public double putOrAdd(int key, double putValue, double incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public double addTo(int key, double additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public double remove(int key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link IntDoubleMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(int key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexReplace(int index, double newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, int key, double value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntFloatAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/IntFloatAssociativeContainer.java deleted file mode 100644 index 50a4b963..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntFloatAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see IntContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface IntFloatAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(int key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntFloatPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntFloatProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntFloatPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public IntCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public FloatContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntFloatHashMap.java b/sources/main/java/com/carrotsearch/hppc/IntFloatHashMap.java deleted file mode 100644 index f7a3a4f5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntFloatHashMap.java +++ /dev/null @@ -1,1081 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of int to float, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class IntFloatHashMap implements IntFloatMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public int[] keys; - - /** The array holding values. */ - public float[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public IntFloatHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntFloatHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public IntFloatHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public IntFloatHashMap(IntFloatAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public float put(int key, float value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - float previousValue = hasEmptyKey ? values[mask + 1] : 0f; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final float previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(IntFloatAssociativeContainer container) { - final int count = size(); - for (IntFloatCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (IntFloatCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public float putOrAdd(int key, float putValue, float incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((float) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public float addTo(int key, float incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public float remove(int key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0f; - } - hasEmptyKey = false; - float previousValue = values[mask + 1]; - values[mask + 1] = 0f; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final float previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof IntLookupContainer) { - if (hasEmptyKey && other.contains(0)) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (IntCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntFloatPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - } - - final int[] keys = this.keys; - final float[] values = this.values; - for (int slot = 0; slot <= mask; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0)) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public float get(int key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0f; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public float getOrDefault(int key, float defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(int key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(int key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public float indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public float indexReplace(int index, float newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - float previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, int key, float value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public float indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - float previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0f; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (IntFloatCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(IntFloatHashMap other) { - if (other.size() != size()) { - return false; - } - - for (IntFloatCursor c : other) { - int key = c.key; - if (!containsKey(key) || !(Float.floatToIntBits(c.value) == Float.floatToIntBits(get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final int[] prevKeys = this.keys; - final float[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntFloatCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new IntFloatCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntFloatCursor fetch() { - final int mask = IntFloatHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final int[] keys = this.keys; - final float[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final int[] keys = this.keys; - final float[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final IntFloatHashMap owner = IntFloatHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntFloatProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntFloatPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(IntPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final int e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = IntFloatHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public FloatCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractFloatCollection { - private final IntFloatHashMap owner = IntFloatHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(float value) { - for (IntFloatCursor c : owner) { - if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (IntFloatCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (IntFloatCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final float e) { - return owner.removeAll( - (key, value) -> (Float.floatToIntBits(e) == Float.floatToIntBits(value))); - } - - @Override - public int removeAll(final FloatPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final FloatCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new FloatCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected FloatCursor fetch() { - final int mask = IntFloatHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public IntFloatHashMap clone() { - try { - - IntFloatHashMap cloned = (IntFloatHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (IntFloatCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static IntFloatHashMap from(int[] keys, float[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - IntFloatHashMap map = new IntFloatHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(int key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(int[] fromKeys, float[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final int[] keys = this.keys; - final float[] values = this.values; - final int mask = this.mask; - int existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - int[] prevKeys = this.keys; - float[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new int[arraySize + emptyElementSlot]); - this.values = (new float[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, int pendingKey, float pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final int[] prevKeys = this.keys; - final float[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final int[] keys = this.keys; - final float[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final int existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0; - values[gapSlot] = 0f; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntFloatMap.java b/sources/main/java/com/carrotsearch/hppc/IntFloatMap.java deleted file mode 100644 index 4a1e2c9b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntFloatMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntFloatCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface IntFloatMap extends IntFloatAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public float get(int key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public float getOrDefault(int key, float defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public float put(int key, float value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(int key, float value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(IntFloatAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public float putOrAdd(int key, float putValue, float incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public float addTo(int key, float additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public float remove(int key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link IntFloatMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(int key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexReplace(int index, float newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, int key, float value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntHashSet.java b/sources/main/java/com/carrotsearch/hppc/IntHashSet.java deleted file mode 100644 index f6aae01d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntHashSet.java +++ /dev/null @@ -1,787 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash set of ints, implemented using open addressing with linear probing for - * collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java") -public class IntHashSet extends AbstractIntCollection - implements IntLookupContainer, IntSet, Preallocable, Cloneable, Accountable { - /** The hash array holding keys. */ - public int[] keys; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any. - * - * @see #size() - * @see #hasEmptyKey - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** - * New instance with sane defaults. - * - * @see #IntHashSet(int, double) - */ - public IntHashSet() { - this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with sane defaults. - * - * @see #IntHashSet(int, double) - */ - public IntHashSet(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public IntHashSet(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** New instance copying elements from another {@link IntContainer}. */ - public IntHashSet(IntContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public boolean add(int key) { - if (((key) == 0)) { - assert ((keys[mask + 1]) == 0); - boolean added = !hasEmptyKey; - hasEmptyKey = true; - return added; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return false; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key); - } else { - keys[slot] = key; - } - - assigned++; - return true; - } - } - - /** - * Adds all elements from the given list (vararg) to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public final int addAll(int... elements) { - ensureCapacity(elements.length); - int count = 0; - for (int e : elements) { - if (add(e)) { - count++; - } - } - return count; - } - - /** - * Adds all elements from the given {@link IntContainer} to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public int addAll(IntContainer container) { - ensureCapacity(container.size()); - return addAll((Iterable) container); - } - - /** - * Adds all elements from the given iterable to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public int addAll(Iterable iterable) { - int count = 0; - for (IntCursor cursor : iterable) { - if (add(cursor.value)) { - count++; - } - } - return count; - } - - /** {@inheritDoc} */ - @Override - public int[] toArray() { - - final int[] cloned = (new int[size()]); - int j = 0; - if (hasEmptyKey) { - cloned[j++] = 0; - } - - final int[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - int existing; - if (!((existing = keys[slot]) == 0)) { - cloned[j++] = existing; - } - } - - return cloned; - } - - /** An alias for the (preferred) {@link #removeAll}. */ - public boolean remove(int key) { - if (((key) == 0)) { - boolean hadEmptyKey = hasEmptyKey; - hasEmptyKey = false; - return hadEmptyKey; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - shiftConflictingKeys(slot); - return true; - } - slot = (slot + 1) & mask; - } - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(int key) { - return remove(key) ? 1 : 0; - } - - /** - * Removes all keys present in a given container. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntContainer other) { - final int before = size(); - - // Try to iterate over the smaller set or over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof IntLookupContainer) { - if (hasEmptyKey && other.contains(0)) { - hasEmptyKey = false; - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (IntCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0)) { - hasEmptyKey = false; - } - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0)) { - if (predicate.apply(existing)) { - shiftConflictingKeys(slot); - continue; // Repeat the check for the same slot i (shifted). - } - } - slot++; - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public boolean contains(int key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - return false; - } - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - Arrays.fill(keys, 0); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - keys = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final int[] prevKeys = this.keys; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys); - } - } - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - final int[] keys = this.keys; - for (int slot = mask; slot >= 0; slot--) { - int existing; - if (!((existing = keys[slot]) == 0)) { - h += BitMixer.mix(existing); - } - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - private boolean sameKeys(IntSet other) { - if (other.size() != size()) { - return false; - } - - for (IntCursor c : other) { - if (!contains(c.value)) { - return false; - } - } - - return true; - } - - /** {@inheritDoc} */ - @Override - public IntHashSet clone() { - try { - - IntHashSet cloned = (IntHashSet) super.clone(); - cloned.keys = keys.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - @Override - public long ramBytesAllocated() { - // int: assigned, mask, keyMixer, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys); - } - - @Override - public long ramBytesUsed() { - // int: assigned, mask, keyMixer, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - protected final class EntryIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = IntHashSet.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - if (hasEmptyKey) { - procedure.apply(0); - } - - final int[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - int existing; - if (!((existing = keys[slot]) == 0)) { - procedure.apply(existing); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - if (hasEmptyKey) { - if (!predicate.apply(0)) { - return predicate; - } - } - - final int[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - int existing; - if (!((existing = keys[slot]) == 0)) { - if (!predicate.apply(existing)) { - break; - } - } - } - - return predicate; - } - - /** - * Create a set from a variable number of arguments or an array of int. The elements - * are copied from the argument to the internal buffer. - */ - public static IntHashSet from(int... elements) { - final IntHashSet set = new IntHashSet(elements.length); - set.addAll(elements); - return set; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(int key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up logic in - * certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between modifications (it will not be affected by read-only - * operations). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the set. - * @return A non-negative value of the logical "index" of the key in the set or a negative value - * if the key did not exist. - */ - public int indexOf(int key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index) { - assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** - * Returns the exact value of the existing key. This method makes sense for sets of objects which - * define custom key-equality relationship. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the equivalent key currently stored in the set. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return keys[index]; - } - - /** - * Replaces the existing equivalent key with the given one and returns any previous value stored - * for that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key - * currently stored at the provided index. - * @return Returns the previous key stored in the set. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexReplace(int index, int equivalentKey) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - assert ((keys[index]) == (equivalentKey)); - - int previousValue = keys[index]; - keys[index] = equivalentKey; - return previousValue; - } - - /** - * Inserts a key for an index that is not present in the set. This method may help in avoiding - * double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public void indexInsert(int index, int key) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - assert ((keys[index]) == 0); - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key); - } else { - keys[index] = key; - } - - assigned++; - } - } - - /** - * Removes a key at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public void indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - if (index > mask) { - hasEmptyKey = false; - } else { - shiftConflictingKeys(index); - } - } - - @Override - public String visualizeKeyDistribution(int characters) { - return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(int[] fromKeys) { - assert HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored keys into the new buffers. - final int[] keys = this.keys; - final int mask = this.mask; - int existing; - for (int i = fromKeys.length - 1; --i >= 0; ) { - if (!((existing = fromKeys[i]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - int[] prevKeys = this.keys; - try { - int emptyElementSlot = 1; - this.keys = (new int[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.keys == null ? 0 : size(), arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key to be inserted into the buffer but there is not - * enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, int pendingKey) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final int[] prevKeys = this.keys; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - - // Rehash old keys, including the pending key. - rehash(prevKeys); - } - - /** Shift all the slot-conflicting keys allocated to (and including) slot. */ - protected void shiftConflictingKeys(int gapSlot) { - final int[] keys = this.keys; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final int existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntIndexedContainer.java b/sources/main/java/com/carrotsearch/hppc/IntIndexedContainer.java deleted file mode 100644 index 0eb076ea..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntIndexedContainer.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.carrotsearch.hppc; - -import java.util.RandomAccess; -import java.util.stream.IntStream; - -/** - * An indexed container provides random access to elements based on an index. Indexes - * are zero-based. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeIndexedContainer.java") -public interface IntIndexedContainer extends IntCollection, RandomAccess { - /** - * Removes the first element that equals e1, returning whether an element has been - * removed. - */ - public boolean removeElement(int e1); - - /** - * Removes the first element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeFirst(int e1); - - /** - * Removes the last element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeLast(int e1); - - /** - * Returns the index of the first occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int indexOf(int e1); - - /** - * Returns the index of the last occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int lastIndexOf(int e1); - - /** Adds an element to the end of this container (the last index is incremented by one). */ - public void add(int e1); - - /** - * Inserts the specified element at the specified position in this list. - * - * @param index The index at which the element should be inserted, shifting any existing and - * subsequent elements to the right. - */ - public void insert(int index, int e1); - - /** - * Replaces the element at the specified position in this list with the specified element. - * - * @return Returns the previous value in the list. - */ - public int set(int index, int e1); - - /** - * @return Returns the element at index index from the list. - */ - public int get(int index); - - /** - * Removes the element at the specified position in this container and returns it. - * - * @see #removeFirst - * @see #removeLast - * @see #removeAll - */ - public int removeAt(int index); - - /** Removes and returns the last element of this container. This container must not be empty. */ - public int removeLast(); - - /** - * Removes from this container all of the elements with indexes between fromIndex, - * inclusive, and toIndex, exclusive. - */ - public void removeRange(int fromIndex, int toIndex); - - /** Returns this container elements as a stream. */ - public IntStream stream(); - - /** Sorts the elements in this container and returns this container. */ - public IntIndexedContainer sort(); - - /** Reverses the elements in this container and returns this container. */ - public IntIndexedContainer reverse(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntIntAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/IntIntAssociativeContainer.java deleted file mode 100644 index fdb8772a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntIntAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see IntContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface IntIntAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(int key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntIntPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntIntProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntIntPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public IntCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public IntContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntIntHashMap.java b/sources/main/java/com/carrotsearch/hppc/IntIntHashMap.java deleted file mode 100644 index 5380245c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntIntHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of int to int, implemented using open addressing with linear - * probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class IntIntHashMap implements IntIntMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public int[] keys; - - /** The array holding values. */ - public int[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public IntIntHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntIntHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public IntIntHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public IntIntHashMap(IntIntAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public int put(int key, int value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - int previousValue = hasEmptyKey ? values[mask + 1] : 0; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final int previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(IntIntAssociativeContainer container) { - final int count = size(); - for (IntIntCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (IntIntCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public int putOrAdd(int key, int putValue, int incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((int) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public int addTo(int key, int incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public int remove(int key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0; - } - hasEmptyKey = false; - int previousValue = values[mask + 1]; - values[mask + 1] = 0; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final int previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof IntLookupContainer) { - if (hasEmptyKey && other.contains(0)) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (IntCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntIntPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - } - - final int[] keys = this.keys; - final int[] values = this.values; - for (int slot = 0; slot <= mask; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0)) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int get(int key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int getOrDefault(int key, int defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(int key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(int key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public int indexReplace(int index, int newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - int previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, int key, int value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public int indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - int previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (IntIntCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(IntIntHashMap other) { - if (other.size() != size()) { - return false; - } - - for (IntIntCursor c : other) { - int key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final int[] prevKeys = this.keys; - final int[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntIntCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new IntIntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntIntCursor fetch() { - final int mask = IntIntHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final int[] keys = this.keys; - final int[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final int[] keys = this.keys; - final int[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final IntIntHashMap owner = IntIntHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntIntProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntIntPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(IntPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final int e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = IntIntHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public IntCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractIntCollection { - private final IntIntHashMap owner = IntIntHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(int value) { - for (IntIntCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (IntIntCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (IntIntCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final int e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final IntPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = IntIntHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public IntIntHashMap clone() { - try { - - IntIntHashMap cloned = (IntIntHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (IntIntCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static IntIntHashMap from(int[] keys, int[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - IntIntHashMap map = new IntIntHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(int key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(int[] fromKeys, int[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final int[] keys = this.keys; - final int[] values = this.values; - final int mask = this.mask; - int existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - int[] prevKeys = this.keys; - int[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new int[arraySize + emptyElementSlot]); - this.values = (new int[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, int pendingKey, int pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final int[] prevKeys = this.keys; - final int[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final int[] keys = this.keys; - final int[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final int existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0; - values[gapSlot] = 0; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntIntMap.java b/sources/main/java/com/carrotsearch/hppc/IntIntMap.java deleted file mode 100644 index 29097ecf..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntIntMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntIntCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface IntIntMap extends IntIntAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public int get(int key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public int getOrDefault(int key, int defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public int put(int key, int value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(int key, int value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(IntIntAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public int putOrAdd(int key, int putValue, int incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public int addTo(int key, int additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public int remove(int key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link IntIntMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(int key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexReplace(int index, int newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, int key, int value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntLongAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/IntLongAssociativeContainer.java deleted file mode 100644 index 37f3887c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntLongAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see IntContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface IntLongAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(int key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntLongPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntLongProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntLongPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public IntCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public LongContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntLongHashMap.java b/sources/main/java/com/carrotsearch/hppc/IntLongHashMap.java deleted file mode 100644 index 8a595142..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntLongHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of int to long, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class IntLongHashMap implements IntLongMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public int[] keys; - - /** The array holding values. */ - public long[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public IntLongHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntLongHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public IntLongHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public IntLongHashMap(IntLongAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public long put(int key, long value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - long previousValue = hasEmptyKey ? values[mask + 1] : 0L; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final long previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(IntLongAssociativeContainer container) { - final int count = size(); - for (IntLongCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (IntLongCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public long putOrAdd(int key, long putValue, long incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((long) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public long addTo(int key, long incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public long remove(int key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0L; - } - hasEmptyKey = false; - long previousValue = values[mask + 1]; - values[mask + 1] = 0L; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final long previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof IntLookupContainer) { - if (hasEmptyKey && other.contains(0)) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (IntCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntLongPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - } - - final int[] keys = this.keys; - final long[] values = this.values; - for (int slot = 0; slot <= mask; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0)) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public long get(int key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0L; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public long getOrDefault(int key, long defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(int key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(int key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public long indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public long indexReplace(int index, long newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - long previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, int key, long value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public long indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - long previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0L; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (IntLongCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(IntLongHashMap other) { - if (other.size() != size()) { - return false; - } - - for (IntLongCursor c : other) { - int key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final int[] prevKeys = this.keys; - final long[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntLongCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new IntLongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntLongCursor fetch() { - final int mask = IntLongHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final int[] keys = this.keys; - final long[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final int[] keys = this.keys; - final long[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final IntLongHashMap owner = IntLongHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntLongProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntLongPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(IntPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final int e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = IntLongHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public LongCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractLongCollection { - private final IntLongHashMap owner = IntLongHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(long value) { - for (IntLongCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (IntLongCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (IntLongCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final long e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final LongPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = IntLongHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public IntLongHashMap clone() { - try { - - IntLongHashMap cloned = (IntLongHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (IntLongCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static IntLongHashMap from(int[] keys, long[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - IntLongHashMap map = new IntLongHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(int key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(int[] fromKeys, long[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final int[] keys = this.keys; - final long[] values = this.values; - final int mask = this.mask; - int existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - int[] prevKeys = this.keys; - long[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new int[arraySize + emptyElementSlot]); - this.values = (new long[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, int pendingKey, long pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final int[] prevKeys = this.keys; - final long[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final int[] keys = this.keys; - final long[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final int existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0; - values[gapSlot] = 0L; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntLongMap.java b/sources/main/java/com/carrotsearch/hppc/IntLongMap.java deleted file mode 100644 index debb6908..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntLongMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntLongCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface IntLongMap extends IntLongAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public long get(int key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public long getOrDefault(int key, long defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public long put(int key, long value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(int key, long value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(IntLongAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public long putOrAdd(int key, long putValue, long incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public long addTo(int key, long additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public long remove(int key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link IntLongMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(int key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexReplace(int index, long newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, int key, long value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntLookupContainer.java b/sources/main/java/com/carrotsearch/hppc/IntLookupContainer.java deleted file mode 100644 index 7eee508f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntLookupContainer.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Marker interface for containers that can check if they contain a given object in at least time - * O(log n) and ideally in amortized constant time O(1). - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeLookupContainer.java") -public interface IntLookupContainer extends IntContainer { - public boolean contains(int e); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntObjectAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/IntObjectAssociativeContainer.java deleted file mode 100644 index 7be49222..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntObjectAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see IntContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface IntObjectAssociativeContainer extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(int key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntObjectPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntObjectProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntObjectPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public IntCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ObjectContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntObjectHashMap.java b/sources/main/java/com/carrotsearch/hppc/IntObjectHashMap.java deleted file mode 100644 index 8fb8f64f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntObjectHashMap.java +++ /dev/null @@ -1,1050 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of int to Object, implemented using open addressing with - * linear probing for collision resolution. Supports null values. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class IntObjectHashMap - implements IntObjectMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public int[] keys; - - /** The array holding values. */ - public Object[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public IntObjectHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntObjectHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public IntObjectHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public IntObjectHashMap(IntObjectAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public VType put(int key, VType value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - VType previousValue = hasEmptyKey ? (VType) values[mask + 1] : null; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final VType previousValue = (VType) values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return null; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(IntObjectAssociativeContainer container) { - final int count = size(); - for (IntObjectCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (IntObjectCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** {@inheritDoc} */ - @Override - public VType remove(int key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return null; - } - hasEmptyKey = false; - VType previousValue = (VType) values[mask + 1]; - values[mask + 1] = null; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final VType previousValue = (VType) values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return null; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof IntLookupContainer) { - if (hasEmptyKey && other.contains(0)) { - hasEmptyKey = false; - values[mask + 1] = null; - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (IntCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntObjectPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0, (VType) values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = null; - } - } - - final int[] keys = this.keys; - final VType[] values = (VType[]) this.values; - for (int slot = 0; slot <= mask; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0)) { - hasEmptyKey = false; - values[mask + 1] = null; - } - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public VType get(int key) { - if (((key) == 0)) { - return hasEmptyKey ? (VType) values[mask + 1] : null; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return (VType) values[slot]; - } - slot = (slot + 1) & mask; - } - - return null; - } - } - - /** {@inheritDoc} */ - @Override - public VType getOrDefault(int key, VType defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? (VType) values[mask + 1] : defaultValue; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return (VType) values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(int key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(int key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public VType indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return (VType) values[index]; - } - - /** {@inheritDoc} */ - @Override - public VType indexReplace(int index, VType newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - VType previousValue = (VType) values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, int key, VType value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public VType indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - VType previousValue = (VType) values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = null; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0); - - Arrays.fill(values, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (IntObjectCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Values are compared - * using {@link Objects#equals(Object)} method. - */ - protected boolean equalElements(IntObjectHashMap other) { - if (other.size() != size()) { - return false; - } - - for (IntObjectCursor c : other) { - int key = c.key; - if (!containsKey(key) || !java.util.Objects.equals(c.value, get(key))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final int[] prevKeys = this.keys; - final VType[] prevValues = (VType[]) this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final IntObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new IntObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntObjectCursor fetch() { - final int mask = IntObjectHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = (VType) values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0; - cursor.value = (VType) values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final int[] keys = this.keys; - final VType[] values = (VType[]) this.values; - - if (hasEmptyKey) { - procedure.apply(0, (VType) values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final int[] keys = this.keys; - final VType[] values = (VType[]) this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0, (VType) values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final IntObjectHashMap owner = IntObjectHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntObjectProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntObjectPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(IntPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final int e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = IntObjectHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ObjectCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractObjectCollection { - private final IntObjectHashMap owner = IntObjectHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(VType value) { - for (IntObjectCursor c : owner) { - if (java.util.Objects.equals(value, c.value)) { - return true; - } - } - return false; - } - - @Override - public > T forEach(T procedure) { - for (IntObjectCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - for (IntObjectCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator> iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final VType e) { - return owner.removeAll((key, value) -> java.util.Objects.equals(e, value)); - } - - @Override - public int removeAll(final ObjectPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = IntObjectHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = (VType) values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = (VType) values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public IntObjectHashMap clone() { - try { - - IntObjectHashMap cloned = (IntObjectHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (IntObjectCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static IntObjectHashMap from(int[] keys, VType[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - IntObjectHashMap map = new IntObjectHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(int key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(int[] fromKeys, VType[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final int[] keys = this.keys; - final VType[] values = (VType[]) this.values; - final int mask = this.mask; - int existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - int[] prevKeys = this.keys; - VType[] prevValues = (VType[]) this.values; - try { - int emptyElementSlot = 1; - this.keys = (new int[arraySize + emptyElementSlot]); - this.values = ((VType[]) new Object[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, int pendingKey, VType pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final int[] prevKeys = this.keys; - final VType[] prevValues = (VType[]) this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final int[] keys = this.keys; - final VType[] values = (VType[]) this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final int existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0; - values[gapSlot] = null; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntObjectMap.java b/sources/main/java/com/carrotsearch/hppc/IntObjectMap.java deleted file mode 100644 index 86c778c7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntObjectMap.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntObjectCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface IntObjectMap extends IntObjectAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public VType get(int key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public VType getOrDefault(int key, VType defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public VType put(int key, VType value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(int key, VType value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(IntObjectAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public VType remove(int key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link IntObjectMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(int key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexReplace(int index, VType newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, int key, VType value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntPgmIndex.java b/sources/main/java/com/carrotsearch/hppc/IntPgmIndex.java deleted file mode 100644 index da7dd0d2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntPgmIndex.java +++ /dev/null @@ -1,600 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntCursor; -import com.carrotsearch.hppc.procedures.IntProcedure; -import java.util.Arrays; -import java.util.Iterator; - -/** - * Space-efficient index that enables fast rank/range search operations on a sorted sequence of - * int. - * - *

Implementation of the PGM-Index described at https://pgm.di.unipi.it/, based on the paper - * - *

- *   Paolo Ferragina and Giorgio Vinciguerra.
- *   The PGM-index: a fully-dynamic compressed learned index with provable worst-case bounds.
- *   PVLDB, 13(8): 1162-1175, 2020.
- * 
- * - * It provides {@code rank} and {@code range} search operations. {@code indexOf()} is faster than - * B+Tree, and the index is much more compact. {@code contains()} is between 4x to 7x slower than - * {@code IntHashSet#contains()}, but between 2.5x to 3x faster than {@link Arrays#binarySearch}. - * - *

Its compactness (40KB for 200MB of keys) makes it efficient for very large collections, the - * index fitting easily in the L2 cache. The {@code epsilon} parameter should be set according to - * the desired space-time trade-off. A smaller value makes the estimation more precise and the range - * smaller but at the cost of increased space usage. In practice, {@code epsilon} 64 is a good sweet - * spot. - * - *

Internally the index uses an optimal piecewise linear mapping from keys to their position in - * the sorted order. This mapping is represented as a sequence of linear models (segments) which are - * themselves recursively indexed by other piecewise linear mappings. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypePgmIndex.java") -public class IntPgmIndex implements Accountable { - - /** Empty immutable IntPgmIndex. */ - public static final IntPgmIndex EMPTY = new IntEmptyPgmIndex(); - - /** - * Epsilon approximation range when searching the list of keys. Controls the size of the returned - * search range, strictly greater than 0. It should be set according to the desired space-time - * trade-off. A smaller value makes the estimation more precise and the range smaller but at the - * cost of increased space usage. - * - *

With EPSILON=64 the benchmark with 200MB of keys shows that this PGM index requires only 2% - * additional memory on average (40KB). It depends on the distribution of the keys. This epsilon - * value is good even for 2MB of keys. With EPSILON=32: +5% speed, but 4x space (160KB). - */ - public static final int EPSILON = 64; - - /** - * Epsilon approximation range for the segments layers. Controls the size of the search range in - * the hierarchical segment lists, strictly greater than 0. - */ - public static final int EPSILON_RECURSIVE = 32; - - /** Size of a key, measured in {@link Integer#BYTES} because the key is stored in an int[]. */ - public static final int KEY_SIZE = - RamUsageEstimator.primitiveSizes.get(int.class) / Integer.BYTES; - - /** 2x {@link #KEY_SIZE}. */ - public static final int DOUBLE_KEY_SIZE = KEY_SIZE * 2; - - /** - * Data size of a segment, measured in {@link Integer#BYTES}, because segments are stored in an - * int[]. - */ - public static final int SEGMENT_DATA_SIZE = KEY_SIZE * 3; - - /** Initial value of the exponential jump when scanning out of the epsilon range. */ - public static final int BEYOND_EPSILON_JUMP = 16; - - /** - * The list of keys for which this index is built. It is sorted and may contain duplicate - * elements. - */ - public final IntArrayList keys; - - /** The size of the key set. That is, the number of distinct elements in {@link #keys}. */ - public final int size; - - /** The lowest key in {@link #keys}. */ - public final int firstKey; - - /** The highest key in {@link #keys}. */ - public final int lastKey; - - /** The epsilon range used to build this index. */ - public final int epsilon; - - /** The recursive epsilon range used to build this index. */ - public final int epsilonRecursive; - - /** The offsets in {@link #segmentData} of the first segment of each segment level. */ - public final int[] levelOffsets; - - /** The index data. It contains all the segments for all the levels. */ - public final int[] segmentData; - - private IntPgmIndex( - IntArrayList keys, - int size, - int epsilon, - int epsilonRecursive, - int[] levelOffsets, - int[] segmentData) { - assert keys.size() > 0; - assert size > 0 && size <= keys.size(); - assert epsilon > 0; - assert epsilonRecursive > 0; - this.keys = keys; - this.size = size; - firstKey = keys.get(0); - lastKey = keys.get(keys.size() - 1); - this.epsilon = epsilon; - this.epsilonRecursive = epsilonRecursive; - this.levelOffsets = levelOffsets; - this.segmentData = segmentData; - } - - /** Empty set constructor. */ - private IntPgmIndex() { - keys = new IntArrayList(0); - size = 0; - firstKey = 0; - lastKey = 0; - epsilon = 0; - epsilonRecursive = 0; - levelOffsets = new int[0]; - segmentData = levelOffsets; - } - - /** Returns the size of the key set. That is, the number of distinct elements in {@link #keys}. */ - public int size() { - return size; - } - - /** Returns whether this key set is empty. */ - public boolean isEmpty() { - return size() == 0; - } - - /** Returns whether this key set contains the given key. */ - public boolean contains(int key) { - return indexOf(key) >= 0; - } - - /** - * Searches the specified key, and returns its index in the element list. If multiple elements are - * equal to the specified key, there is no guarantee which one will be found. - * - * @return The index of the searched key if it is present; otherwise, {@code (-(insertion - * point) - 1)}. The insertion point is defined as the point at which the key would - * be inserted into the list: the index of the first element greater than the key, or {@link - * #keys}#{@code size()} if all the elements are less than the specified key. Note that this - * guarantees that the return value will be >= 0 if and only if the key is found. - */ - public int indexOf(int key) { - if (key < firstKey) { - return -1; - } - if (key > lastKey) { - return -keys.size() - 1; - } - final int[] segmentData = this.segmentData; - int segmentDataIndex = findSegment(key); - int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); - int index = - Math.min( - approximateIndex(key, segmentDataIndex, segmentData), - Math.min(nextIntercept, keys.size() - 1)); - assert index >= 0 && index < keys.size(); - int k = keys.get(index); - if (key < k) { - // Scan sequentially before the approximated index, within epsilon range. - final int fromIndex = Math.max(index - epsilon - 1, 0); - while (--index >= fromIndex) { - k = keys.get(index); - if (key > k) { - return -index - 2; - } - if (((key) == (k))) { - return index; - } - } - // Continue scanning out of the epsilon range. - // This might happen in rare cases of precision error during the approximation - // computation for longs (we don't have long double 128 bits in Java). - // This might also happen in rare corner cases of large duplicate elements - // sequence at the epsilon range boundary. - index++; - int jump = BEYOND_EPSILON_JUMP; - do { - int loIndex = Math.max(index - jump, 0); - if (key >= keys.get(loIndex)) { - return Arrays.binarySearch(keys.buffer, loIndex, index, key); - } - index = loIndex; - jump <<= 1; - } while (index > 0); - return -1; - } else if (((key) == (k))) { - return index; - } else { - // Scan sequentially after the approximated index, within epsilon range. - final int toIndex = Math.min(index + epsilon + 3, keys.size()); - while (++index < toIndex) { - k = keys.get(index); - if (key < k) { - return -index - 1; - } - if (((key) == (k))) { - return index; - } - } - // Continue scanning out of the epsilon range. - int jump = BEYOND_EPSILON_JUMP; - do { - int hiIndex = Math.min(index + jump, keys.size()); - if (key <= keys.get(hiIndex)) { - return Arrays.binarySearch(keys.buffer, index, hiIndex, key); - } - index = hiIndex; - jump <<= 1; - } while (index < keys.size()); - return -keys.size() - 1; - } - } - - /** - * Returns, for any value {@code x}, the number of keys in the sorted list which are smaller than - * {@code x}. It is equal to {@link #indexOf} if {@code x} belongs to the list, or -{@link - * #indexOf}-1 otherwise. - * - *

If multiple elements are equal to the specified key, there is no guarantee which one will be - * found. - * - * @return The index of the searched key if it is present; otherwise, the {@code insertion point}. - * The insertion point is defined as the point at which the key would be inserted into - * the list: the index of the first element greater than the key, or {@link #keys}#{@code - * size()} if all the elements are less than the specified key. Note that this method always - * returns a value >= 0. - */ - public int rank(int x) { - int index = indexOf(x); - return index >= 0 ? index : -index - 1; - } - - /** - * Returns the number of keys in the list that are greater than or equal to {@code minKey} - * (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public int rangeCardinality(int minKey, int maxKey) { - int fromIndex = rank(minKey); - int maxIndex = indexOf(maxKey); - int toIndex = maxIndex >= 0 ? maxIndex + 1 : -maxIndex - 1; - return Math.max(toIndex - fromIndex, 0); - } - - /** - * Returns an iterator over the keys in the list that are greater than or equal to {@code minKey} - * (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public Iterator rangeIterator(int minKey, int maxKey) { - int fromIndex = rank(minKey); - return new RangeIterator(keys, fromIndex, maxKey); - } - - /** - * Applies {@code procedure} to the keys in the list that are greater than or equal to {@code - * minKey} (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public T forEachInRange(T procedure, int minKey, int maxKey) { - final int[] buffer = keys.buffer; - int k; - for (int i = rank(minKey), size = keys.size(); i < size && (k = buffer[i]) <= maxKey; i++) { - procedure.apply(k); - } - return procedure; - } - - /** - * Estimates the allocated memory. It does not count the memory for the list of keys, only for the - * index itself. - */ - @Override - public long ramBytesAllocated() { - // int: size, epsilon, epsilonRecursive - // int: firstKey, lastKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 3 * Integer.BYTES - + 2L * KEY_SIZE * Integer.BYTES - // + keys.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(levelOffsets) - + RamUsageEstimator.shallowSizeOfArray(segmentData); - } - - /** - * Estimates the bytes that are actually used. It does not count the memory for the list of keys, - * only for the index itself. - */ - @Override - public long ramBytesUsed() { - // int: size, epsilon, epsilonRecursive - // int: firstKey, lastKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 3 * Integer.BYTES - + 2L * KEY_SIZE * Integer.BYTES - // + keys.ramBytesUsed() - + RamUsageEstimator.shallowSizeOfArray(levelOffsets) - + RamUsageEstimator.shallowSizeOfArray(segmentData); - } - - /** - * Finds the segment responsible for a given key, that is, the rightmost segment having its first - * key <= the searched key. - * - * @return the segment data index; or -1 if none. - */ - private int findSegment(int key) { - assert key >= firstKey && key <= lastKey; - final int epsilonRecursive = this.epsilonRecursive; - final int[] levelOffsets = this.levelOffsets; - final int[] segmentData = this.segmentData; - int level = levelOffsets.length - 1; - int segmentDataIndex = levelOffsets[level] * SEGMENT_DATA_SIZE; - while (--level >= 0) { - int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); - int index = Math.min(approximateIndex(key, segmentDataIndex, segmentData), nextIntercept); - assert index >= 0 && index <= levelOffsets[level + 1] - levelOffsets[level] - 1; - int sdIndex = (levelOffsets[level] + index) * SEGMENT_DATA_SIZE; - if (getKey(sdIndex, segmentData) <= key) { - // Scan sequentially segments after the approximated index, within the epsilon range. - final int levelNumSegments = levelOffsets[level + 1] - levelOffsets[level] - 1; - final int toIndex = Math.min(index + epsilonRecursive + 3, levelNumSegments); - while (index++ < toIndex && getKey(sdIndex + SEGMENT_DATA_SIZE, segmentData) <= key) { - sdIndex += SEGMENT_DATA_SIZE; - } - } else { - // Scan sequentially segments before the approximated index, within the epsilon range. - final int fromIndex = Math.max(index - epsilonRecursive - 1, 0); - while (index-- > fromIndex) { - sdIndex -= SEGMENT_DATA_SIZE; - if (getKey(sdIndex, segmentData) <= key) { - break; - } - } - } - segmentDataIndex = sdIndex; - } - assert segmentDataIndex >= 0; - return segmentDataIndex; - } - - private int approximateIndex(int key, int segmentDataIndex, int[] segmentData) { - long intercept = getIntercept(segmentDataIndex, segmentData); - int sKey = getKey(segmentDataIndex, segmentData); - double slope = getSlope(segmentDataIndex, segmentData); - int index = (int) (slope * ((double) key - sKey) + intercept); - return Math.max(index, 0); - } - - private static long getIntercept(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getIntercept(segmentDataIndex, segmentData, KEY_SIZE); - } - - private int getKey(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0); - } - - private static double getSlope(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getSlope(segmentDataIndex + DOUBLE_KEY_SIZE, segmentData, KEY_SIZE); - } - - /** Empty immutable PGM Index. */ - private static class IntEmptyPgmIndex extends IntPgmIndex { - - private final Iterator emptyIterator = new IntEmptyIterator(); - - @Override - public int indexOf(int key) { - return -1; - } - - @Override - public Iterator rangeIterator(int minKey, int maxKey) { - return emptyIterator; - } - - @Override - public T forEachInRange(T procedure, int minKey, int maxKey) { - return procedure; - } - - private static class IntEmptyIterator extends AbstractIterator { - @Override - protected IntCursor fetch() { - return done(); - } - } - } - - /** Iterator over a range of elements in a sorted array. */ - protected static class RangeIterator extends AbstractIterator { - private final int[] buffer; - private final int size; - private final IntCursor cursor; - private final int maxKey; - - /** Range iterator from {@code fromIndex} (inclusive) to {@code maxKey} (inclusive). */ - protected RangeIterator(IntArrayList keys, int fromIndex, int maxKey) { - this.buffer = keys.buffer; - this.size = keys.size(); - this.cursor = new IntCursor(); - this.cursor.index = fromIndex; - this.maxKey = maxKey; - } - - @Override - protected IntCursor fetch() { - if (cursor.index >= size) { - return done(); - } - cursor.value = buffer[cursor.index++]; - if (cursor.value > maxKey) { - cursor.index = size; - return done(); - } - return cursor; - } - } - - /** Builds a {@link IntPgmIndex} on a provided sorted list of keys. */ - public static class IntBuilder implements PlaModel.SegmentConsumer, Accountable { - - protected IntArrayList keys; - protected int epsilon = EPSILON; - protected int epsilonRecursive = EPSILON_RECURSIVE; - protected PlaModel plam; - protected int size; - protected IntArrayList segmentData; - protected int numSegments; - - /** Sets the sorted list of keys to build the index for; duplicate elements are allowed. */ - public IntBuilder setSortedKeys(IntArrayList keys) { - this.keys = keys; - return this; - } - - /** Sets the sorted array of keys to build the index for; duplicate elements are allowed. */ - public IntBuilder setSortedKeys(int[] keys, int length) { - IntArrayList keyList = new IntArrayList(0); - keyList.buffer = keys; - keyList.elementsCount = length; - return setSortedKeys(keyList); - } - - /** Sets the epsilon range to use when learning the segments for the list of keys. */ - public IntBuilder setEpsilon(int epsilon) { - if (epsilon <= 0) { - throw new IllegalArgumentException("epsilon must be > 0"); - } - this.epsilon = epsilon; - return this; - } - - /** - * Sets the recursive epsilon range to use when learning the segments for the segment levels. - */ - public IntBuilder setEpsilonRecursive(int epsilonRecursive) { - if (epsilonRecursive <= 0) { - throw new IllegalArgumentException("epsilonRecursive must be > 0"); - } - this.epsilonRecursive = epsilonRecursive; - return this; - } - - /** Builds the {@link IntPgmIndex}; or {@link #EMPTY} if there are no keys in the list. */ - public IntPgmIndex build() { - if (keys == null || keys.size() == 0) { - return (IntPgmIndex) EMPTY; - } - plam = new PlaModel(epsilon); - - int segmentsInitialCapacity = - Math.min( - Math.max(keys.size() / (2 * epsilon * epsilon) * SEGMENT_DATA_SIZE, 16), 1 << 19); - segmentData = new IntArrayList(segmentsInitialCapacity); - IntArrayList levelOffsets = new IntArrayList(16); - - int levelOffset = 0; - levelOffsets.add(levelOffset); - int levelNumSegments = buildFirstLevel(); - while (levelNumSegments > 1) { - int nextLevelOffset = numSegments; - levelOffsets.add(nextLevelOffset); - levelNumSegments = buildUpperLevel(levelOffset, levelNumSegments); - levelOffset = nextLevelOffset; - } - - int[] segmentDataFinal = segmentData.toArray(); - int[] levelOffsetsFinal = levelOffsets.toArray(); - return new IntPgmIndex( - keys, size, epsilon, epsilonRecursive, levelOffsetsFinal, segmentDataFinal); - } - - private int buildFirstLevel() { - assert numSegments == 0; - int numKeys = keys.size(); - int size = 0; - int key = keys.get(0); - size++; - plam.addKey(key, 0, this); - for (int i = 1; i < numKeys; i++) { - int nextKey = keys.get(i); - if (!((nextKey) == (key))) { - key = nextKey; - plam.addKey(key, i, this); - size++; - } - } - plam.finish(this); - addSentinelSegment(numKeys); - this.size = size; - return numSegments - 1; - } - - private int buildUpperLevel(int levelOffset, int levelNumSegments) { - plam.setEpsilon(epsilonRecursive); - assert numSegments > 0; - int initialNumSegments = numSegments; - int segmentDataIndex = levelOffset * SEGMENT_DATA_SIZE; - int key = getKey(segmentDataIndex, segmentData.buffer); - plam.addKey(key, 0, this); - for (int i = 1; i < levelNumSegments; i++) { - segmentDataIndex += SEGMENT_DATA_SIZE; - int nextKey = getKey(segmentDataIndex, segmentData.buffer); - if (!((nextKey) == (key))) { - key = nextKey; - plam.addKey(key, i, this); - } - } - plam.finish(this); - addSentinelSegment(levelNumSegments); - return numSegments - initialNumSegments - 1; - } - - private int getKey(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0); - } - - /** - * Adds a sentinel segment that is used to give a limit for the position approximation, but does - * not count in the number of segments per level. - */ - private void addSentinelSegment(int endIndex) { - // This sentinel segment is used in findSegment(). - accept(Double.MAX_VALUE, 0d, endIndex); - } - - @Override - public void accept(double firstKey, double slope, long intercept) { - PgmIndexUtil.addIntercept(intercept, segmentData, KEY_SIZE); - PgmIndexUtil.addKey((int) firstKey, segmentData); - PgmIndexUtil.addSlope(slope, segmentData, KEY_SIZE); - numSegments++; - assert segmentData.size() == numSegments * SEGMENT_DATA_SIZE; - } - - /** - * Estimates the allocated memory. It does not count the memory for the list of keys, only for - * the builder itself. - */ - @Override - public long ramBytesAllocated() { - // int: epsilon, epsilonRecursive, size, numSegments - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - // + keys.ramBytesAllocated() - + plam.ramBytesAllocated() - + segmentData.ramBytesAllocated(); - } - - /** - * Estimates the bytes that are actually used. It does not count the memory for the list of - * keys, only for the builder itself. - */ - @Override - public long ramBytesUsed() { - // int: epsilon, epsilonRecursive, size, numSegments - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - // + keys.ramBytesUsed() - + plam.ramBytesUsed() - + segmentData.ramBytesUsed(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntSet.java b/sources/main/java/com/carrotsearch/hppc/IntSet.java deleted file mode 100644 index 500b376e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntSet.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** A set of ints. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java") -public interface IntSet extends IntCollection { - /** - * Adds k to the set. - * - * @return Returns true if this element was not part of the set before. Returns - * false if an equal element is already part of the set, does not replace the - * existing element with the argument. - */ - public boolean add(int k); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); - - /** - * Adds all elements from the given {@link IntContainer} to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - * @since 0.9.1 - */ - public int addAll(IntContainer container); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntShortAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/IntShortAssociativeContainer.java deleted file mode 100644 index 918efde7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntShortAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see IntContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface IntShortAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(int key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(IntShortPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntShortProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link IntShortPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public IntCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ShortContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntShortHashMap.java b/sources/main/java/com/carrotsearch/hppc/IntShortHashMap.java deleted file mode 100644 index c36b0fe2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntShortHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of int to short, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class IntShortHashMap implements IntShortMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public int[] keys; - - /** The array holding values. */ - public short[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public IntShortHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntShortHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public IntShortHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public IntShortHashMap(IntShortAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public short put(int key, short value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - short previousValue = hasEmptyKey ? values[mask + 1] : ((short) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final short previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(IntShortAssociativeContainer container) { - final int count = size(); - for (IntShortCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (IntShortCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public short putOrAdd(int key, short putValue, short incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((short) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public short addTo(int key, short incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public short remove(int key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((short) 0); - } - hasEmptyKey = false; - short previousValue = values[mask + 1]; - values[mask + 1] = ((short) 0); - return previousValue; - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final short previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof IntLookupContainer) { - if (hasEmptyKey && other.contains(0)) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (IntCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntShortPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - } - - final int[] keys = this.keys; - final short[] values = this.values; - for (int slot = 0; slot <= mask; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(IntPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0)) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - } - - final int[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - int existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public short get(int key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((short) 0); - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public short getOrDefault(int key, short defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(int key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final int[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(int key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final int[] keys = this.keys; - int slot = hashKey(key) & mask; - - int existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public short indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public short indexReplace(int index, short newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - short previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, int key, short value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public short indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - short previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((short) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (IntShortCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(IntShortHashMap other) { - if (other.size() != size()) { - return false; - } - - for (IntShortCursor c : other) { - int key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final int[] prevKeys = this.keys; - final short[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new IntShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntShortCursor fetch() { - final int mask = IntShortHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final int[] keys = this.keys; - final short[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final int[] keys = this.keys; - final short[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final IntShortHashMap owner = IntShortHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntShortProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntShortPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(IntPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final int e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = IntShortHashMap.this.mask; - while (index <= mask) { - int existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ShortCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractShortCollection { - private final IntShortHashMap owner = IntShortHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(short value) { - for (IntShortCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (IntShortCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (IntShortCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final short e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final ShortPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = IntShortHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public IntShortHashMap clone() { - try { - - IntShortHashMap cloned = (IntShortHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (IntShortCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static IntShortHashMap from(int[] keys, short[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - IntShortHashMap map = new IntShortHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(int key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(int[] fromKeys, short[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final int[] keys = this.keys; - final short[] values = this.values; - final int mask = this.mask; - int existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - int[] prevKeys = this.keys; - short[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new int[arraySize + emptyElementSlot]); - this.values = (new short[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, int pendingKey, short pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final int[] prevKeys = this.keys; - final short[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final int[] keys = this.keys; - final short[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final int existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0; - values[gapSlot] = ((short) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntShortMap.java b/sources/main/java/com/carrotsearch/hppc/IntShortMap.java deleted file mode 100644 index b0a5813a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntShortMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntShortCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface IntShortMap extends IntShortAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public short get(int key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public short getOrDefault(int key, short defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public short put(int key, short value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(int key, short value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(IntShortAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public short putOrAdd(int key, short putValue, short incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public short addTo(int key, short additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public short remove(int key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link IntShortMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(int key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexReplace(int index, short newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, int key, short value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/IntStack.java b/sources/main/java/com/carrotsearch/hppc/IntStack.java deleted file mode 100644 index cd65ff61..00000000 --- a/sources/main/java/com/carrotsearch/hppc/IntStack.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.IntCursor; - -/** - * A subclass of {@link IntArrayList} adding stack-related utility methods. The top of the stack is - * at the {@link #size()} - 1 element. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") -public class IntStack extends IntArrayList { - /** New instance with sane defaults. */ - public IntStack() { - super(); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public IntStack(int expectedElements) { - super(expectedElements); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public IntStack(int expectedElements, ArraySizingStrategy resizer) { - super(expectedElements, resizer); - } - - /** Create a stack by pushing all elements of another container to it. */ - public IntStack(IntContainer container) { - super(container); - } - - /** Adds one int to the stack. */ - public void push(int e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** Adds two ints to the stack. */ - public void push(int e1, int e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Adds three ints to the stack. */ - public void push(int e1, int e2, int e3) { - ensureBufferSpace(3); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - } - - /** Adds four ints to the stack. */ - public void push(int e1, int e2, int e3, int e4) { - ensureBufferSpace(4); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - buffer[elementsCount++] = e4; - } - - /** Add a range of array elements to the stack. */ - public void push(int[] elements, int start, int len) { - assert start >= 0 && len >= 0; - - ensureBufferSpace(len); - System.arraycopy(elements, start, buffer, elementsCount, len); - elementsCount += len; - } - - /** - * Vararg-signature method for pushing elements at the top of the stack. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void push(int... elements) { - push(elements, 0, elements.length); - } - - /** Pushes all elements from another container to the top of the stack. */ - public int pushAll(IntContainer container) { - return addAll(container); - } - - /** Pushes all elements from another iterable to the top of the stack. */ - public int pushAll(Iterable iterable) { - return addAll(iterable); - } - - /** Discard an arbitrary number of elements from the top of the stack. */ - public void discard(int count) { - assert elementsCount >= count; - - elementsCount -= count; - } - - /** Discard the top element from the stack. */ - public void discard() { - assert elementsCount > 0; - - elementsCount--; - } - - /** Remove the top element from the stack and return it. */ - public int pop() { - return removeLast(); - } - - /** Peek at the top element on the stack. */ - public int peek() { - assert elementsCount > 0; - return buffer[elementsCount - 1]; - } - - /** Create a stack by pushing a variable number of arguments to it. */ - public static IntStack from(int... elements) { - final IntStack stack = new IntStack(elements.length); - stack.push(elements); - return stack; - } - - /** {@inheritDoc} */ - @Override - public IntStack clone() { - return (IntStack) super.clone(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongArrayDeque.java b/sources/main/java/com/carrotsearch/hppc/LongArrayDeque.java deleted file mode 100644 index 8065aafd..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongArrayDeque.java +++ /dev/null @@ -1,776 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.LongCursor; -import com.carrotsearch.hppc.predicates.LongPredicate; -import com.carrotsearch.hppc.procedures.LongProcedure; -import java.util.*; - -/** An array-backed {@link LongDeque}. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") -public class LongArrayDeque extends AbstractLongCollection - implements LongDeque, Preallocable, Cloneable, Accountable { - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** Internal array for storing elements of the deque. */ - public long[] buffer = LongArrayList.EMPTY_ARRAY; - - /** - * The index of the element at the head of the deque or an arbitrary number equal to tail if the - * deque is empty. - */ - public int head; - - /** The index at which the next element would be added to the tail of the deque. */ - public int tail; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public LongArrayDeque() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongArrayDeque(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public LongArrayDeque(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - ensureCapacity(expectedElements); - } - - /** - * Creates a new deque from elements of another container, appending elements at the end of the - * deque in the iteration order. - */ - public LongArrayDeque(LongContainer container) { - this(container.size()); - addLast(container); - } - - /** {@inheritDoc} */ - @Override - public void addFirst(long e1) { - int h = oneLeft(head, buffer.length); - if (h == tail) { - ensureBufferSpace(1); - h = oneLeft(head, buffer.length); - } - buffer[head = h] = e1; - } - - /** - * Vararg-signature method for adding elements at the front of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to add. - */ - public final void addFirst(long... elements) { - ensureBufferSpace(elements.length); - for (long k : elements) { - addFirst(k); - } - } - - /** - * Inserts all elements from the given container to the front of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(LongContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (LongCursor cursor : container) { - addFirst(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the front of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(Iterable iterable) { - int size = 0; - for (LongCursor cursor : iterable) { - addFirst(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void addLast(long e1) { - int t = oneRight(tail, buffer.length); - if (head == t) { - ensureBufferSpace(1); - t = oneRight(tail, buffer.length); - } - buffer[tail] = e1; - tail = t; - } - - /** - * Vararg-signature method for adding elements at the end of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to iterate over. - */ - public final void addLast(long... elements) { - ensureBufferSpace(1); - for (long k : elements) { - addLast(k); - } - } - - /** - * Inserts all elements from the given container to the end of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(LongContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (LongCursor cursor : container) { - addLast(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the end of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(Iterable iterable) { - int size = 0; - for (LongCursor cursor : iterable) { - addLast(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public long removeFirst() { - assert size() > 0 : "The deque is empty."; - - final long result = buffer[head]; - buffer[head] = 0L; - head = oneRight(head, buffer.length); - return result; - } - - /** {@inheritDoc} */ - @Override - public long removeLast() { - assert size() > 0 : "The deque is empty."; - - tail = oneLeft(tail, buffer.length); - final long result = buffer[tail]; - buffer[tail] = 0L; - return result; - } - - /** {@inheritDoc} */ - @Override - public long getFirst() { - assert size() > 0 : "The deque is empty."; - - return buffer[head]; - } - - /** {@inheritDoc} */ - @Override - public long getLast() { - assert size() > 0 : "The deque is empty."; - - return buffer[oneLeft(tail, buffer.length)]; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(long e1) { - final int index = bufferIndexOf(e1); - if (index >= 0) removeAtBufferIndex(index); - return index; - } - - /** - * Return the index of the first (counting from head) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int bufferIndexOf(long e1) { - final int last = tail; - final int bufLen = buffer.length; - for (int i = head; i != last; i = oneRight(i, bufLen)) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(long e1) { - final int index = lastBufferIndexOf(e1); - if (index >= 0) { - removeAtBufferIndex(index); - } - return index; - } - - /** - * Return the index of the last (counting from tail) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int lastBufferIndexOf(long e1) { - final int bufLen = buffer.length; - final int last = oneLeft(head, bufLen); - for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { - if (((e1) == (buffer[i]))) return i; - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(long e1) { - int removed = 0; - final int last = tail; - final int bufLen = buffer.length; - int from, to; - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (((e1) == (buffer[from]))) { - buffer[from] = 0L; - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0L; - } - - to = oneRight(to, bufLen); - } - - tail = to; - return removed; - } - - /** - * Removes the element at index in the internal {#link {@link #buffer} array, - * returning its value. - * - * @param index Index of the element to remove. The index must be located between {@link #head} - * and {@link #tail} in modulo {@link #buffer} arithmetic. - */ - public void removeAtBufferIndex(int index) { - assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) - : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; - - // Cache fields in locals (hopefully moved to registers). - final long[] buffer = this.buffer; - final int bufLen = buffer.length; - final int lastIndex = bufLen - 1; - final int head = this.head; - final int tail = this.tail; - - final int leftChunk = Math.abs(index - head) % bufLen; - final int rightChunk = Math.abs(tail - index) % bufLen; - - if (leftChunk < rightChunk) { - if (index >= head) { - System.arraycopy(buffer, head, buffer, head + 1, leftChunk); - } else { - System.arraycopy(buffer, 0, buffer, 1, index); - buffer[0] = buffer[lastIndex]; - System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); - } - buffer[head] = 0L; - this.head = oneRight(head, bufLen); - } else { - if (index < tail) { - System.arraycopy(buffer, index + 1, buffer, index, rightChunk); - } else { - System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); - buffer[lastIndex] = buffer[0]; - System.arraycopy(buffer, 1, buffer, 0, tail); - } - buffer[tail] = 0L; - this.tail = oneLeft(tail, bufLen); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int size() { - if (head <= tail) return tail - head; - else return (tail - head + buffer.length); - } - - /** - * {@inheritDoc} - * - *

The internal array buffers are not released as a result of this call. - * - * @see #release() - */ - @Override - public void clear() { - if (head < tail) { - Arrays.fill(buffer, head, tail, 0L); - } else { - Arrays.fill(buffer, 0, tail, 0L); - Arrays.fill(buffer, head, buffer.length, 0L); - } - this.head = tail = 0; - } - - /** Release internal buffers of this deque and reallocate with the default buffer. */ - public void release() { - this.head = tail = 0; - buffer = LongArrayList.EMPTY_ARRAY; - ensureBufferSpace(0); - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - ensureBufferSpace(expectedElements - size()); - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = buffer.length; - final int elementsCount = size(); - - if (elementsCount + expectedAdditions >= bufferLen) { - final int emptySlot = 1; // deque invariant: always an empty slot. - final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); - assert newSize >= (elementsCount + expectedAdditions + emptySlot) - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - try { - final long[] newBuffer = (new long[newSize]); - if (bufferLen > 0) { - toArray(newBuffer); - tail = elementsCount; - head = 0; - } - this.buffer = newBuffer; - } catch (OutOfMemoryError e) { - throw new BufferAllocationException( - "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); - } - } - } - - /** {@inheritDoc} */ - @Override - public long[] toArray() { - - final int size = size(); - return toArray((new long[size])); - } - - /** - * Copies elements of this deque to an array. The content of the target array is - * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). - * - * @param target The target array must be large enough to hold all elements. - * @return Returns the target argument for chaining. - */ - public long[] toArray(long[] target) { - assert target.length >= size() : "Target array must be >= " + size(); - - if (head < tail) { - // The contents is not wrapped around. Just copy. - System.arraycopy(buffer, head, target, 0, size()); - } else if (head > tail) { - // The contents is split. Merge elements from the following indexes: - // [head...buffer.length - 1][0, tail - 1] - final int rightCount = buffer.length - head; - System.arraycopy(buffer, head, target, 0, rightCount); - System.arraycopy(buffer, 0, target, rightCount, tail); - } - - return target; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public LongArrayDeque clone() { - try { - - LongArrayDeque cloned = (LongArrayDeque) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Move one index to the left, wrapping around buffer. */ - protected static int oneLeft(int index, int modulus) { - if (index >= 1) { - return index - 1; - } - return modulus - 1; - } - - /** Move one index to the right, wrapping around buffer. */ - protected static int oneRight(int index, int modulus) { - if (index + 1 == modulus) { - return 0; - } - return index + 1; - } - - @Override - public long ramBytesAllocated() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); - } - - /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ - private final class ValueIterator extends AbstractIterator { - private final LongCursor cursor; - private int remaining; - - public ValueIterator() { - cursor = new LongCursor(); - cursor.index = oneLeft(head, buffer.length); - this.remaining = size(); - } - - @Override - protected LongCursor fetch() { - if (remaining == 0) { - return done(); - } - - remaining--; - cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; - return cursor; - } - } - - /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ - private final class DescendingValueIterator extends AbstractIterator { - private final LongCursor cursor; - private int remaining; - - public DescendingValueIterator() { - cursor = new LongCursor(); - cursor.index = tail; - this.remaining = size(); - } - - @Override - protected LongCursor fetch() { - if (remaining == 0) return done(); - - remaining--; - cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; - return cursor; - } - } - - /** - * Returns a cursor over the values of this deque (in head to tail order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *

-   * for (IntValueCursor c : intDeque) {
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator() { - return new ValueIterator(); - } - - /** - * Returns a cursor over the values of this deque (in tail to head order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *
-   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
-   *   final IntCursor c = i.next();
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator descendingIterator() { - return new DescendingValueIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - forEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, fromIndex, inclusive, to - * toIndex, exclusive. - */ - private void forEach(LongProcedure procedure, int fromIndex, final int toIndex) { - final long[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - procedure.apply(buffer[i]); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - int fromIndex = head; - int toIndex = tail; - - final long[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (!predicate.apply(buffer[i])) { - break; - } - } - - return predicate; - } - - /** Applies procedure to all elements of this deque, tail to head. */ - @Override - public T descendingForEach(T procedure) { - descendingForEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive. - */ - private void descendingForEach(LongProcedure procedure, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final long[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - procedure.apply(buffer[i]); - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public T descendingForEach(T predicate) { - descendingForEach(predicate, head, tail); - return predicate; - } - - /** - * Applies predicate to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive or until the predicate returns false. - */ - private void descendingForEach(LongPredicate predicate, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final long[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - if (!predicate.apply(buffer[i])) { - break; - } - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - final long[] buffer = this.buffer; - final int last = tail; - final int bufLen = buffer.length; - int removed = 0; - int from, to; - from = to = head; - try { - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (predicate.apply(buffer[from])) { - buffer[from] = 0L; - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0L; - } - - to = oneRight(to, bufLen); - } - } finally { - // Keep the deque in consistent state even if the predicate throws an exception. - for (; from != last; from = oneRight(from, bufLen)) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0L; - } - - to = oneRight(to, bufLen); - } - tail = to; - } - - return removed; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(long e) { - int fromIndex = head; - int toIndex = tail; - - final long[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (((e) == (buffer[i]))) { - return true; - } - } - - return false; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1; - int fromIndex = head; - int toIndex = tail; - - final long[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare order-aligned elements against another {@link LongDeque}. */ - protected boolean equalElements(LongArrayDeque other) { - int max = size(); - if (other.size() != max) { - return false; - } - - Iterator i1 = this.iterator(); - Iterator i2 = other.iterator(); - - while (i1.hasNext() && i2.hasNext()) { - if (!((i1.next().value) == (i2.next().value))) { - return false; - } - } - - return !i1.hasNext() && !i2.hasNext(); - } - - /** Create a new deque by pushing a variable number of arguments to the end of it. */ - public static LongArrayDeque from(long... elements) { - final LongArrayDeque coll = new LongArrayDeque(elements.length); - coll.addLast(elements); - return coll; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongArrayList.java b/sources/main/java/com/carrotsearch/hppc/LongArrayList.java deleted file mode 100644 index ea99bfeb..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongArrayList.java +++ /dev/null @@ -1,586 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.LongPredicate; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; -import java.util.stream.LongStream; - -/** An array-backed list of longs. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") -public class LongArrayList extends AbstractLongCollection - implements LongIndexedContainer, Preallocable, Cloneable, Accountable { - /** An immutable empty buffer (array). */ - public static final long[] EMPTY_ARRAY = new long[0]; - - ; - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** - * Internal array for storing the list. The array may be larger than the current size ({@link - * #size()}). - */ - public long[] buffer = EMPTY_ARRAY; - - /** Current number of elements stored in {@link #buffer}. */ - public int elementsCount; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public LongArrayList() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongArrayList(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public LongArrayList(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - buffer = Arrays.copyOf(buffer, expectedElements); - } - - /** Creates a new list from the elements of another container in its iteration order. */ - public LongArrayList(LongContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public void add(long e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** - * Appends two elements at the end of the list. To add more than two elements, use add - * (vararg-version) or access the buffer directly (tight loop). - */ - public void add(long e1, long e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Add all elements from a range of given array to the list. */ - public void add(long[] elements, int start, int length) { - assert length >= 0 : "Length must be >= 0"; - - ensureBufferSpace(length); - System.arraycopy(elements, start, buffer, elementsCount, length); - elementsCount += length; - } - - /** - * Vararg-signature method for adding elements at the end of the list. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void add(long... elements) { - add(elements, 0, elements.length); - } - - /** Adds all elements from another container. */ - public int addAll(LongContainer container) { - final int size = container.size(); - ensureBufferSpace(size); - - for (LongCursor cursor : container) { - add(cursor.value); - } - - return size; - } - - /** Adds all elements from another iterable. */ - public int addAll(Iterable iterable) { - int size = 0; - for (LongCursor cursor : iterable) { - add(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void insert(int index, long e1) { - assert (index >= 0 && index <= size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; - - ensureBufferSpace(1); - System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); - buffer[index] = e1; - elementsCount++; - } - - /** {@inheritDoc} */ - @Override - public long get(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - return buffer[index]; - } - - /** {@inheritDoc} */ - @Override - public long set(int index, long e1) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final long v = buffer[index]; - buffer[index] = e1; - return v; - } - - /** {@inheritDoc} */ - @Override - public long removeAt(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final long v = buffer[index]; - System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); - - return v; - } - - /** {@inheritDoc} */ - @Override - public long removeLast() { - assert elementsCount > 0; - - final long v = buffer[--elementsCount]; - - return v; - } - - /** {@inheritDoc} */ - @Override - public void removeRange(int fromIndex, int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); - final int count = toIndex - fromIndex; - elementsCount -= count; - } - - /** {@inheritDoc} */ - @Override - public boolean removeElement(long e1) { - return removeFirst(e1) != -1; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(long e1) { - final int index = indexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(long e1) { - final int index = lastIndexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(long e1) { - int to = 0; - for (int from = 0; from < elementsCount; from++) { - if (((e1) == (buffer[from]))) { - continue; - } - if (to != from) { - buffer[to] = buffer[from]; - } - to++; - } - final int deleted = elementsCount - to; - this.elementsCount = to; - - return deleted; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(long e1) { - return indexOf(e1) >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexOf(long e1) { - for (int i = 0; i < elementsCount; i++) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int lastIndexOf(long e1) { - for (int i = elementsCount - 1; i >= 0; i--) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return elementsCount == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (expectedElements > bufferLen) { - ensureBufferSpace(expectedElements - size()); - } - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (elementsCount + expectedAdditions > bufferLen) { - final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); - assert newSize >= elementsCount + expectedAdditions - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - this.buffer = Arrays.copyOf(buffer, newSize); - } - } - - /** - * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be - * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated - * values will be reset to the default value (zero). If the list is expanded, the elements beyond - * the current size are initialized with JVM-defaults (zero or null values). - */ - public void resize(int newSize) { - if (newSize <= buffer.length) { - if (newSize < elementsCount) { - Arrays.fill(buffer, newSize, elementsCount, 0L); - } else { - Arrays.fill(buffer, elementsCount, newSize, 0L); - } - } else { - ensureCapacity(newSize); - } - this.elementsCount = newSize; - } - - /** {@inheritDoc} */ - @Override - public int size() { - return elementsCount; - } - - /** Trim the internal buffer to the current size. */ - public void trimToSize() { - if (size() != this.buffer.length) { - this.buffer = toArray(); - } - } - - /** - * Sets the number of stored elements to zero. Releases and initializes the internal storage array - * to default values. To clear the list without cleaning the buffer, simply set the {@link - * #elementsCount} field to zero. - */ - @Override - public void clear() { - Arrays.fill(buffer, 0, elementsCount, 0L); - this.elementsCount = 0; - } - - /** Sets the number of stored elements to zero and releases the internal storage array. */ - @Override - public void release() { - this.buffer = EMPTY_ARRAY; - this.elementsCount = 0; - } - - /** - * {@inheritDoc} - * - *

The returned array is sized to match exactly the number of elements of the stack. - */ - @Override - public long[] toArray() { - - return Arrays.copyOf(buffer, elementsCount); - } - - @Override - public LongStream stream() { - - return Arrays.stream(buffer, 0, size()); - } - - /** {@inheritDoc} */ - @Override - public LongIndexedContainer sort() { - Arrays.sort(buffer, 0, elementsCount); - return this; - } - - /** {@inheritDoc} */ - @Override - public LongIndexedContainer reverse() { - for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { - long tmp = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = tmp; - } - return this; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public LongArrayList clone() { - try { - - final LongArrayList cloned = (LongArrayList) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1, max = elementsCount; - for (int i = 0; i < max; i++) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare index-aligned elements against another {@link LongIndexedContainer}. */ - protected boolean equalElements(LongArrayList other) { - int max = size(); - if (other.size() != max) { - return false; - } - - for (int i = 0; i < max; i++) { - if (!((get(i)) == (other.get(i)))) { - return false; - } - } - - return true; - } - - @Override - public long ramBytesAllocated() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); - } - - /** An iterator implementation for {@link LongArrayList#iterator}. */ - static final class ValueIterator extends AbstractIterator { - private final LongCursor cursor; - - private final long[] buffer; - private final int size; - - public ValueIterator(long[] buffer, int size) { - this.cursor = new LongCursor(); - this.cursor.index = -1; - this.size = size; - this.buffer = buffer; - } - - @Override - protected LongCursor fetch() { - if (cursor.index + 1 == size) return done(); - - cursor.value = buffer[++cursor.index]; - return cursor; - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new ValueIterator(buffer, size()); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - return forEach(procedure, 0, size()); - } - - /** - * Applies procedure to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive. - */ - public T forEach(T procedure, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final long[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - procedure.apply(buffer[i]); - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - final long[] buffer = this.buffer; - final int elementsCount = this.elementsCount; - int to = 0; - int from = 0; - try { - for (; from < elementsCount; from++) { - if (predicate.apply(buffer[from])) { - buffer[from] = 0L; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0L; - } - to++; - } - } finally { - // Keep the list in a consistent state, even if the predicate throws an exception. - for (; from < elementsCount; from++) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = 0L; - } - to++; - } - - this.elementsCount = to; - } - - return elementsCount - to; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - return forEach(predicate, 0, size()); - } - - /** - * Applies predicate to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive, or until predicate returns false. - */ - public T forEach(T predicate, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final long[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - if (!predicate.apply(buffer[i])) break; - } - - return predicate; - } - - /** - * Create a list from a variable number of arguments or an array of long. The - * elements are copied from the argument to the internal buffer. - */ - public static LongArrayList from(long... elements) { - final LongArrayList list = new LongArrayList(elements.length); - list.add(elements); - return list; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongBufferVisualizer.java b/sources/main/java/com/carrotsearch/hppc/LongBufferVisualizer.java deleted file mode 100644 index 1c9e0af9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongBufferVisualizer.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Reused buffer visualization routines. - * - * @see LongSet#visualizeKeyDistribution(int) - * @see LongVTypeMap#visualizeKeyDistribution(int) - */ -class LongBufferVisualizer { - static String visualizeKeyDistribution(long[] buffer, int max, int characters) { - final StringBuilder b = new StringBuilder(); - final char[] chars = ".123456789X".toCharArray(); - for (int i = 1, start = -1; i <= characters; i++) { - int end = (int) ((long) i * max / characters); - - if (start + 1 <= end) { - int taken = 0; - int slots = 0; - for (int slot = start + 1; slot <= end; slot++, slots++) { - if (!((buffer[slot]) == 0)) { - taken++; - } - } - b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); - start = end; - } - } - while (b.length() < characters) { - b.append(' '); - } - return b.toString(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongByteAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/LongByteAssociativeContainer.java deleted file mode 100644 index b3e17bfa..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongByteAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see LongContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface LongByteAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(long key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongBytePredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongByteProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongBytePredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public LongCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ByteContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongByteHashMap.java b/sources/main/java/com/carrotsearch/hppc/LongByteHashMap.java deleted file mode 100644 index eeaf5028..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongByteHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of long to byte, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class LongByteHashMap implements LongByteMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public long[] keys; - - /** The array holding values. */ - public byte[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public LongByteHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongByteHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public LongByteHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public LongByteHashMap(LongByteAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public byte put(long key, byte value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - byte previousValue = hasEmptyKey ? values[mask + 1] : ((byte) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final byte previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(LongByteAssociativeContainer container) { - final int count = size(); - for (LongByteCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (LongByteCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public byte putOrAdd(long key, byte putValue, byte incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((byte) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public byte addTo(long key, byte incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public byte remove(long key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((byte) 0); - } - hasEmptyKey = false; - byte previousValue = values[mask + 1]; - values[mask + 1] = ((byte) 0); - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final byte previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof LongLookupContainer) { - if (hasEmptyKey && other.contains(0L)) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (LongCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongBytePredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0L, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - } - - final long[] keys = this.keys; - final byte[] values = this.values; - for (int slot = 0; slot <= mask; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0L)) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public byte get(long key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((byte) 0); - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public byte getOrDefault(long key, byte defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(long key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(long key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public byte indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public byte indexReplace(int index, byte newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - byte previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, long key, byte value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public byte indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - byte previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((byte) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0L); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (LongByteCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(LongByteHashMap other) { - if (other.size() != size()) { - return false; - } - - for (LongByteCursor c : other) { - long key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final long[] prevKeys = this.keys; - final byte[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongByteCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new LongByteCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongByteCursor fetch() { - final int mask = LongByteHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0L; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final long[] keys = this.keys; - final byte[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0L, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final long[] keys = this.keys; - final byte[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0L, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final LongByteHashMap owner = LongByteHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongByteProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongBytePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(LongPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final long e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = LongByteHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0L; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ByteCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractByteCollection { - private final LongByteHashMap owner = LongByteHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(byte value) { - for (LongByteCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (LongByteCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (LongByteCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final byte e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final BytePredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ByteCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ByteCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ByteCursor fetch() { - final int mask = LongByteHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public LongByteHashMap clone() { - try { - - LongByteHashMap cloned = (LongByteHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (LongByteCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static LongByteHashMap from(long[] keys, byte[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - LongByteHashMap map = new LongByteHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(long key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(long[] fromKeys, byte[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final long[] keys = this.keys; - final byte[] values = this.values; - final int mask = this.mask; - long existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - long[] prevKeys = this.keys; - byte[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new long[arraySize + emptyElementSlot]); - this.values = (new byte[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, long pendingKey, byte pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final long[] prevKeys = this.keys; - final byte[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final long[] keys = this.keys; - final byte[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final long existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0L; - values[gapSlot] = ((byte) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongByteMap.java b/sources/main/java/com/carrotsearch/hppc/LongByteMap.java deleted file mode 100644 index 1291678d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongByteMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongByteCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface LongByteMap extends LongByteAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public byte get(long key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public byte getOrDefault(long key, byte defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public byte put(long key, byte value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(long key, byte value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(LongByteAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public byte putOrAdd(long key, byte putValue, byte incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public byte addTo(long key, byte additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public byte remove(long key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link LongByteMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(long key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexReplace(int index, byte newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, long key, byte value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongCharAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/LongCharAssociativeContainer.java deleted file mode 100644 index 9188f4e5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongCharAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see LongContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface LongCharAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(long key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongCharPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongCharProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongCharPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public LongCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public CharContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongCharHashMap.java b/sources/main/java/com/carrotsearch/hppc/LongCharHashMap.java deleted file mode 100644 index c5262ab9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongCharHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of long to char, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class LongCharHashMap implements LongCharMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public long[] keys; - - /** The array holding values. */ - public char[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public LongCharHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongCharHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public LongCharHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public LongCharHashMap(LongCharAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public char put(long key, char value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - char previousValue = hasEmptyKey ? values[mask + 1] : ((char) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final char previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(LongCharAssociativeContainer container) { - final int count = size(); - for (LongCharCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (LongCharCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public char putOrAdd(long key, char putValue, char incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((char) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public char addTo(long key, char incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public char remove(long key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((char) 0); - } - hasEmptyKey = false; - char previousValue = values[mask + 1]; - values[mask + 1] = ((char) 0); - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final char previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof LongLookupContainer) { - if (hasEmptyKey && other.contains(0L)) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (LongCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongCharPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0L, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - } - - final long[] keys = this.keys; - final char[] values = this.values; - for (int slot = 0; slot <= mask; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0L)) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public char get(long key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((char) 0); - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public char getOrDefault(long key, char defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(long key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(long key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public char indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public char indexReplace(int index, char newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - char previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, long key, char value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public char indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - char previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((char) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0L); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (LongCharCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(LongCharHashMap other) { - if (other.size() != size()) { - return false; - } - - for (LongCharCursor c : other) { - long key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final long[] prevKeys = this.keys; - final char[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongCharCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new LongCharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCharCursor fetch() { - final int mask = LongCharHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0L; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final long[] keys = this.keys; - final char[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0L, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final long[] keys = this.keys; - final char[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0L, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final LongCharHashMap owner = LongCharHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongCharProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongCharPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(LongPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final long e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = LongCharHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0L; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public CharCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractCharCollection { - private final LongCharHashMap owner = LongCharHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(char value) { - for (LongCharCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (LongCharCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (LongCharCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final char e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final CharPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = LongCharHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public LongCharHashMap clone() { - try { - - LongCharHashMap cloned = (LongCharHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (LongCharCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static LongCharHashMap from(long[] keys, char[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - LongCharHashMap map = new LongCharHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(long key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(long[] fromKeys, char[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final long[] keys = this.keys; - final char[] values = this.values; - final int mask = this.mask; - long existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - long[] prevKeys = this.keys; - char[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new long[arraySize + emptyElementSlot]); - this.values = (new char[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, long pendingKey, char pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final long[] prevKeys = this.keys; - final char[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final long[] keys = this.keys; - final char[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final long existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0L; - values[gapSlot] = ((char) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongCharMap.java b/sources/main/java/com/carrotsearch/hppc/LongCharMap.java deleted file mode 100644 index fbc9d681..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongCharMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongCharCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface LongCharMap extends LongCharAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public char get(long key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public char getOrDefault(long key, char defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public char put(long key, char value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(long key, char value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(LongCharAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public char putOrAdd(long key, char putValue, char incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public char addTo(long key, char additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public char remove(long key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link LongCharMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(long key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexReplace(int index, char newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, long key, char value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongCollection.java b/sources/main/java/com/carrotsearch/hppc/LongCollection.java deleted file mode 100644 index 65869b85..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongCollection.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.predicates.LongPredicate; - -/** - * A collection allows basic, efficient operations on sets of elements (difference and - * intersection). - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") -public interface LongCollection extends LongContainer { - /** - * Removes all occurrences of e from this collection. - * - * @param e Element to be removed from this collection, if present. - * @return The number of removed elements as a result of this call. - */ - public int removeAll(long e); - - /** - * Removes all elements in this collection that are present in c. - * - * @return Returns the number of removed elements. - */ - public int removeAll(LongLookupContainer c); - - /** - * Removes all elements in this collection for which the given predicate returns true - * . - * - * @return Returns the number of removed elements. - */ - public int removeAll(LongPredicate predicate); - - /** - * Keeps all elements in this collection that are present in c. Runs in time - * proportional to the number of elements in this collection. Equivalent of sets intersection. - * - * @return Returns the number of removed elements. - */ - public int retainAll(LongLookupContainer c); - - /** - * Keeps all elements in this collection for which the given predicate returns true. - * - * @return Returns the number of removed elements. - */ - public int retainAll(LongPredicate predicate); - - /** - * Removes all elements from this collection. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongContainer.java b/sources/main/java/com/carrotsearch/hppc/LongContainer.java deleted file mode 100644 index cc10b05a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongContainer.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongCursor; -import com.carrotsearch.hppc.predicates.LongPredicate; -import com.carrotsearch.hppc.procedures.LongProcedure; -import java.util.Iterator; - -/** A generic container holding longs. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") -public interface LongContainer extends Iterable { - /** - * Returns an iterator to a cursor traversing the collection. The order of traversal is not - * defined. More than one cursor may be active at a time. The behavior of iterators is undefined - * if structural changes are made to the underlying collection. - * - *

The iterator is implemented as a cursor and it returns the same cursor instance on - * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current - * list's value (or index in the list) use the cursor's public fields. An example is shown below. - * - *

-   * for (LongCursor<long> c : container) {
-   *   System.out.println("index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator(); - - /** - * Lookup a given element in the container. This operation has no speed guarantees (may be linear - * with respect to the size of this container). - * - * @return Returns true if this container has an element equal to e. - */ - public boolean contains(long e); - - /** - * Return the current number of elements in this container. The time for calculating the - * container's size may take O(n) time, although implementing classes should try to - * maintain the current size and return in constant time. - */ - public int size(); - - /** Shortcut for size() == 0. */ - public boolean isEmpty(); - - /** - * Copies all elements of this container to an array. - * - *

The returned array is always a copy, regardless of the storage used by the container. - */ - public long[] toArray(); - - /** - * Applies a procedure to all container elements. Returns the argument (any subclass - * of {@link LongProcedure}. This lets the caller to call methods of the argument by chaining the - * call (even if the argument is an anonymous type) to retrieve computed values, for example - * (IntContainer): - * - *

-   * int count = container.forEach(new IntProcedure() {
-   *   int count; // this is a field declaration in an anonymous class.
-   *
-   *   public void apply(int value) {
-   *     count++;
-   *   }
-   * }).count;
-   * 
- */ - public T forEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T forEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongDeque.java b/sources/main/java/com/carrotsearch/hppc/LongDeque.java deleted file mode 100644 index a2a202b9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongDeque.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongCursor; -import com.carrotsearch.hppc.predicates.LongPredicate; -import com.carrotsearch.hppc.procedures.LongProcedure; -import java.util.Deque; -import java.util.Iterator; - -/** - * A linear collection that supports element insertion and removal at both ends. - * - * @see Deque - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") -public interface LongDeque extends LongCollection { - /** - * Removes the first element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeFirst(long e); - - /** - * Removes the last element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeLast(long e); - - /** Inserts the specified element at the front of this deque. */ - public void addFirst(long e); - - /** Inserts the specified element at the end of this deque. */ - public void addLast(long e); - - /** - * Retrieves and removes the first element of this deque. - * - * @return the head (first) element of this deque. - */ - public long removeFirst(); - - /** - * Retrieves and removes the last element of this deque. - * - * @return the tail of this deque. - */ - public long removeLast(); - - /** - * Retrieves the first element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public long getFirst(); - - /** - * Retrieves the last element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public long getLast(); - - /** - * @return An iterator over elements in this deque in tail-to-head order. - */ - public Iterator descendingIterator(); - - /** Applies a procedure to all elements in tail-to-head order. */ - public T descendingForEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T descendingForEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongDoubleAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/LongDoubleAssociativeContainer.java deleted file mode 100644 index f0ec0558..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongDoubleAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see LongContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface LongDoubleAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *
-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(long key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongDoublePredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongDoubleProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongDoublePredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public LongCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public DoubleContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongDoubleHashMap.java b/sources/main/java/com/carrotsearch/hppc/LongDoubleHashMap.java deleted file mode 100644 index 2df0b5ab..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongDoubleHashMap.java +++ /dev/null @@ -1,1082 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of long to double, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class LongDoubleHashMap implements LongDoubleMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public long[] keys; - - /** The array holding values. */ - public double[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public LongDoubleHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongDoubleHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public LongDoubleHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public LongDoubleHashMap(LongDoubleAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public double put(long key, double value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - double previousValue = hasEmptyKey ? values[mask + 1] : 0d; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final double previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(LongDoubleAssociativeContainer container) { - final int count = size(); - for (LongDoubleCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (LongDoubleCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public double putOrAdd(long key, double putValue, double incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((double) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public double addTo(long key, double incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public double remove(long key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0d; - } - hasEmptyKey = false; - double previousValue = values[mask + 1]; - values[mask + 1] = 0d; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final double previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof LongLookupContainer) { - if (hasEmptyKey && other.contains(0L)) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (LongCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongDoublePredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0L, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - } - - final long[] keys = this.keys; - final double[] values = this.values; - for (int slot = 0; slot <= mask; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0L)) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public double get(long key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0d; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public double getOrDefault(long key, double defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(long key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(long key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public double indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public double indexReplace(int index, double newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - double previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, long key, double value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public double indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - double previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0d; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0L); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (LongDoubleCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(LongDoubleHashMap other) { - if (other.size() != size()) { - return false; - } - - for (LongDoubleCursor c : other) { - long key = c.key; - if (!containsKey(key) - || !(Double.doubleToLongBits(c.value) == Double.doubleToLongBits(get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final long[] prevKeys = this.keys; - final double[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongDoubleCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new LongDoubleCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongDoubleCursor fetch() { - final int mask = LongDoubleHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0L; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final long[] keys = this.keys; - final double[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0L, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final long[] keys = this.keys; - final double[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0L, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final LongDoubleHashMap owner = LongDoubleHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongDoubleProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongDoublePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(LongPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final long e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = LongDoubleHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0L; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public DoubleCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractDoubleCollection { - private final LongDoubleHashMap owner = LongDoubleHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(double value) { - for (LongDoubleCursor c : owner) { - if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (LongDoubleCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (LongDoubleCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final double e) { - return owner.removeAll( - (key, value) -> (Double.doubleToLongBits(e) == Double.doubleToLongBits(value))); - } - - @Override - public int removeAll(final DoublePredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final DoubleCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new DoubleCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected DoubleCursor fetch() { - final int mask = LongDoubleHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public LongDoubleHashMap clone() { - try { - - LongDoubleHashMap cloned = (LongDoubleHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (LongDoubleCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static LongDoubleHashMap from(long[] keys, double[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - LongDoubleHashMap map = new LongDoubleHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(long key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(long[] fromKeys, double[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final long[] keys = this.keys; - final double[] values = this.values; - final int mask = this.mask; - long existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - long[] prevKeys = this.keys; - double[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new long[arraySize + emptyElementSlot]); - this.values = (new double[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, long pendingKey, double pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final long[] prevKeys = this.keys; - final double[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final long[] keys = this.keys; - final double[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final long existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0L; - values[gapSlot] = 0d; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongDoubleMap.java b/sources/main/java/com/carrotsearch/hppc/LongDoubleMap.java deleted file mode 100644 index 7c83d309..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongDoubleMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongDoubleCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface LongDoubleMap extends LongDoubleAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public double get(long key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public double getOrDefault(long key, double defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public double put(long key, double value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(long key, double value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(LongDoubleAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public double putOrAdd(long key, double putValue, double incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public double addTo(long key, double additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public double remove(long key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link LongDoubleMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(long key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexReplace(int index, double newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, long key, double value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongFloatAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/LongFloatAssociativeContainer.java deleted file mode 100644 index 80cc2da1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongFloatAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see LongContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface LongFloatAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(long key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongFloatPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongFloatProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongFloatPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public LongCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public FloatContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongFloatHashMap.java b/sources/main/java/com/carrotsearch/hppc/LongFloatHashMap.java deleted file mode 100644 index bc0d5f2d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongFloatHashMap.java +++ /dev/null @@ -1,1081 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of long to float, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class LongFloatHashMap implements LongFloatMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public long[] keys; - - /** The array holding values. */ - public float[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public LongFloatHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongFloatHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public LongFloatHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public LongFloatHashMap(LongFloatAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public float put(long key, float value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - float previousValue = hasEmptyKey ? values[mask + 1] : 0f; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final float previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(LongFloatAssociativeContainer container) { - final int count = size(); - for (LongFloatCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (LongFloatCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public float putOrAdd(long key, float putValue, float incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((float) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public float addTo(long key, float incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public float remove(long key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0f; - } - hasEmptyKey = false; - float previousValue = values[mask + 1]; - values[mask + 1] = 0f; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final float previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof LongLookupContainer) { - if (hasEmptyKey && other.contains(0L)) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (LongCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongFloatPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0L, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - } - - final long[] keys = this.keys; - final float[] values = this.values; - for (int slot = 0; slot <= mask; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0L)) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public float get(long key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0f; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public float getOrDefault(long key, float defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(long key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(long key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public float indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public float indexReplace(int index, float newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - float previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, long key, float value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public float indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - float previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0f; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0L); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (LongFloatCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(LongFloatHashMap other) { - if (other.size() != size()) { - return false; - } - - for (LongFloatCursor c : other) { - long key = c.key; - if (!containsKey(key) || !(Float.floatToIntBits(c.value) == Float.floatToIntBits(get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final long[] prevKeys = this.keys; - final float[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongFloatCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new LongFloatCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongFloatCursor fetch() { - final int mask = LongFloatHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0L; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final long[] keys = this.keys; - final float[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0L, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final long[] keys = this.keys; - final float[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0L, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final LongFloatHashMap owner = LongFloatHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongFloatProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongFloatPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(LongPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final long e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = LongFloatHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0L; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public FloatCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractFloatCollection { - private final LongFloatHashMap owner = LongFloatHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(float value) { - for (LongFloatCursor c : owner) { - if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (LongFloatCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (LongFloatCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final float e) { - return owner.removeAll( - (key, value) -> (Float.floatToIntBits(e) == Float.floatToIntBits(value))); - } - - @Override - public int removeAll(final FloatPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final FloatCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new FloatCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected FloatCursor fetch() { - final int mask = LongFloatHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public LongFloatHashMap clone() { - try { - - LongFloatHashMap cloned = (LongFloatHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (LongFloatCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static LongFloatHashMap from(long[] keys, float[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - LongFloatHashMap map = new LongFloatHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(long key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(long[] fromKeys, float[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final long[] keys = this.keys; - final float[] values = this.values; - final int mask = this.mask; - long existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - long[] prevKeys = this.keys; - float[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new long[arraySize + emptyElementSlot]); - this.values = (new float[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, long pendingKey, float pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final long[] prevKeys = this.keys; - final float[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final long[] keys = this.keys; - final float[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final long existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0L; - values[gapSlot] = 0f; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongFloatMap.java b/sources/main/java/com/carrotsearch/hppc/LongFloatMap.java deleted file mode 100644 index dc4cf199..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongFloatMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongFloatCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface LongFloatMap extends LongFloatAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public float get(long key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public float getOrDefault(long key, float defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public float put(long key, float value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(long key, float value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(LongFloatAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public float putOrAdd(long key, float putValue, float incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public float addTo(long key, float additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public float remove(long key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link LongFloatMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(long key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexReplace(int index, float newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, long key, float value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongHashSet.java b/sources/main/java/com/carrotsearch/hppc/LongHashSet.java deleted file mode 100644 index 8957939d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongHashSet.java +++ /dev/null @@ -1,787 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash set of longs, implemented using open addressing with linear probing for - * collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java") -public class LongHashSet extends AbstractLongCollection - implements LongLookupContainer, LongSet, Preallocable, Cloneable, Accountable { - /** The hash array holding keys. */ - public long[] keys; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any. - * - * @see #size() - * @see #hasEmptyKey - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** - * New instance with sane defaults. - * - * @see #LongHashSet(int, double) - */ - public LongHashSet() { - this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with sane defaults. - * - * @see #LongHashSet(int, double) - */ - public LongHashSet(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public LongHashSet(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** New instance copying elements from another {@link LongContainer}. */ - public LongHashSet(LongContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public boolean add(long key) { - if (((key) == 0)) { - assert ((keys[mask + 1]) == 0); - boolean added = !hasEmptyKey; - hasEmptyKey = true; - return added; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return false; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key); - } else { - keys[slot] = key; - } - - assigned++; - return true; - } - } - - /** - * Adds all elements from the given list (vararg) to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public final int addAll(long... elements) { - ensureCapacity(elements.length); - int count = 0; - for (long e : elements) { - if (add(e)) { - count++; - } - } - return count; - } - - /** - * Adds all elements from the given {@link LongContainer} to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public int addAll(LongContainer container) { - ensureCapacity(container.size()); - return addAll((Iterable) container); - } - - /** - * Adds all elements from the given iterable to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public int addAll(Iterable iterable) { - int count = 0; - for (LongCursor cursor : iterable) { - if (add(cursor.value)) { - count++; - } - } - return count; - } - - /** {@inheritDoc} */ - @Override - public long[] toArray() { - - final long[] cloned = (new long[size()]); - int j = 0; - if (hasEmptyKey) { - cloned[j++] = 0L; - } - - final long[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - long existing; - if (!((existing = keys[slot]) == 0)) { - cloned[j++] = existing; - } - } - - return cloned; - } - - /** An alias for the (preferred) {@link #removeAll}. */ - public boolean remove(long key) { - if (((key) == 0)) { - boolean hadEmptyKey = hasEmptyKey; - hasEmptyKey = false; - return hadEmptyKey; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - shiftConflictingKeys(slot); - return true; - } - slot = (slot + 1) & mask; - } - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(long key) { - return remove(key) ? 1 : 0; - } - - /** - * Removes all keys present in a given container. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongContainer other) { - final int before = size(); - - // Try to iterate over the smaller set or over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof LongLookupContainer) { - if (hasEmptyKey && other.contains(0L)) { - hasEmptyKey = false; - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (LongCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0L)) { - hasEmptyKey = false; - } - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0)) { - if (predicate.apply(existing)) { - shiftConflictingKeys(slot); - continue; // Repeat the check for the same slot i (shifted). - } - } - slot++; - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public boolean contains(long key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - return false; - } - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - Arrays.fill(keys, 0L); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - keys = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final long[] prevKeys = this.keys; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys); - } - } - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - final long[] keys = this.keys; - for (int slot = mask; slot >= 0; slot--) { - long existing; - if (!((existing = keys[slot]) == 0)) { - h += BitMixer.mix(existing); - } - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - private boolean sameKeys(LongSet other) { - if (other.size() != size()) { - return false; - } - - for (LongCursor c : other) { - if (!contains(c.value)) { - return false; - } - } - - return true; - } - - /** {@inheritDoc} */ - @Override - public LongHashSet clone() { - try { - - LongHashSet cloned = (LongHashSet) super.clone(); - cloned.keys = keys.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - @Override - public long ramBytesAllocated() { - // int: assigned, mask, keyMixer, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys); - } - - @Override - public long ramBytesUsed() { - // int: assigned, mask, keyMixer, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - protected final class EntryIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = LongHashSet.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0L; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - if (hasEmptyKey) { - procedure.apply(0L); - } - - final long[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - long existing; - if (!((existing = keys[slot]) == 0)) { - procedure.apply(existing); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - if (hasEmptyKey) { - if (!predicate.apply(0L)) { - return predicate; - } - } - - final long[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - long existing; - if (!((existing = keys[slot]) == 0)) { - if (!predicate.apply(existing)) { - break; - } - } - } - - return predicate; - } - - /** - * Create a set from a variable number of arguments or an array of long. The elements - * are copied from the argument to the internal buffer. - */ - public static LongHashSet from(long... elements) { - final LongHashSet set = new LongHashSet(elements.length); - set.addAll(elements); - return set; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(long key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up logic in - * certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between modifications (it will not be affected by read-only - * operations). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the set. - * @return A non-negative value of the logical "index" of the key in the set or a negative value - * if the key did not exist. - */ - public int indexOf(long key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index) { - assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** - * Returns the exact value of the existing key. This method makes sense for sets of objects which - * define custom key-equality relationship. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the equivalent key currently stored in the set. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return keys[index]; - } - - /** - * Replaces the existing equivalent key with the given one and returns any previous value stored - * for that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key - * currently stored at the provided index. - * @return Returns the previous key stored in the set. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexReplace(int index, long equivalentKey) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - assert ((keys[index]) == (equivalentKey)); - - long previousValue = keys[index]; - keys[index] = equivalentKey; - return previousValue; - } - - /** - * Inserts a key for an index that is not present in the set. This method may help in avoiding - * double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public void indexInsert(int index, long key) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - assert ((keys[index]) == 0); - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key); - } else { - keys[index] = key; - } - - assigned++; - } - } - - /** - * Removes a key at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public void indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - if (index > mask) { - hasEmptyKey = false; - } else { - shiftConflictingKeys(index); - } - } - - @Override - public String visualizeKeyDistribution(int characters) { - return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(long[] fromKeys) { - assert HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored keys into the new buffers. - final long[] keys = this.keys; - final int mask = this.mask; - long existing; - for (int i = fromKeys.length - 1; --i >= 0; ) { - if (!((existing = fromKeys[i]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - long[] prevKeys = this.keys; - try { - int emptyElementSlot = 1; - this.keys = (new long[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.keys == null ? 0 : size(), arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key to be inserted into the buffer but there is not - * enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, long pendingKey) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final long[] prevKeys = this.keys; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - - // Rehash old keys, including the pending key. - rehash(prevKeys); - } - - /** Shift all the slot-conflicting keys allocated to (and including) slot. */ - protected void shiftConflictingKeys(int gapSlot) { - final long[] keys = this.keys; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final long existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0L; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongIndexedContainer.java b/sources/main/java/com/carrotsearch/hppc/LongIndexedContainer.java deleted file mode 100644 index ba0c78a2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongIndexedContainer.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.carrotsearch.hppc; - -import java.util.RandomAccess; -import java.util.stream.LongStream; - -/** - * An indexed container provides random access to elements based on an index. Indexes - * are zero-based. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeIndexedContainer.java") -public interface LongIndexedContainer extends LongCollection, RandomAccess { - /** - * Removes the first element that equals e1, returning whether an element has been - * removed. - */ - public boolean removeElement(long e1); - - /** - * Removes the first element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeFirst(long e1); - - /** - * Removes the last element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeLast(long e1); - - /** - * Returns the index of the first occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int indexOf(long e1); - - /** - * Returns the index of the last occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int lastIndexOf(long e1); - - /** Adds an element to the end of this container (the last index is incremented by one). */ - public void add(long e1); - - /** - * Inserts the specified element at the specified position in this list. - * - * @param index The index at which the element should be inserted, shifting any existing and - * subsequent elements to the right. - */ - public void insert(int index, long e1); - - /** - * Replaces the element at the specified position in this list with the specified element. - * - * @return Returns the previous value in the list. - */ - public long set(int index, long e1); - - /** - * @return Returns the element at index index from the list. - */ - public long get(int index); - - /** - * Removes the element at the specified position in this container and returns it. - * - * @see #removeFirst - * @see #removeLast - * @see #removeAll - */ - public long removeAt(int index); - - /** Removes and returns the last element of this container. This container must not be empty. */ - public long removeLast(); - - /** - * Removes from this container all of the elements with indexes between fromIndex, - * inclusive, and toIndex, exclusive. - */ - public void removeRange(int fromIndex, int toIndex); - - /** Returns this container elements as a stream. */ - public LongStream stream(); - - /** Sorts the elements in this container and returns this container. */ - public LongIndexedContainer sort(); - - /** Reverses the elements in this container and returns this container. */ - public LongIndexedContainer reverse(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongIntAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/LongIntAssociativeContainer.java deleted file mode 100644 index 97467873..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongIntAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see LongContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface LongIntAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(long key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongIntPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongIntProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongIntPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public LongCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public IntContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongIntHashMap.java b/sources/main/java/com/carrotsearch/hppc/LongIntHashMap.java deleted file mode 100644 index de4d34b4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongIntHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of long to int, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class LongIntHashMap implements LongIntMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public long[] keys; - - /** The array holding values. */ - public int[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public LongIntHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongIntHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public LongIntHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public LongIntHashMap(LongIntAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public int put(long key, int value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - int previousValue = hasEmptyKey ? values[mask + 1] : 0; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final int previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(LongIntAssociativeContainer container) { - final int count = size(); - for (LongIntCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (LongIntCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public int putOrAdd(long key, int putValue, int incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((int) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public int addTo(long key, int incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public int remove(long key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0; - } - hasEmptyKey = false; - int previousValue = values[mask + 1]; - values[mask + 1] = 0; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final int previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof LongLookupContainer) { - if (hasEmptyKey && other.contains(0L)) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (LongCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongIntPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0L, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - } - - final long[] keys = this.keys; - final int[] values = this.values; - for (int slot = 0; slot <= mask; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0L)) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int get(long key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int getOrDefault(long key, int defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(long key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(long key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public int indexReplace(int index, int newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - int previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, long key, int value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public int indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - int previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0L); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (LongIntCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(LongIntHashMap other) { - if (other.size() != size()) { - return false; - } - - for (LongIntCursor c : other) { - long key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final long[] prevKeys = this.keys; - final int[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongIntCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new LongIntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongIntCursor fetch() { - final int mask = LongIntHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0L; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final long[] keys = this.keys; - final int[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0L, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final long[] keys = this.keys; - final int[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0L, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final LongIntHashMap owner = LongIntHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongIntProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongIntPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(LongPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final long e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = LongIntHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0L; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public IntCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractIntCollection { - private final LongIntHashMap owner = LongIntHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(int value) { - for (LongIntCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (LongIntCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (LongIntCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final int e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final IntPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = LongIntHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public LongIntHashMap clone() { - try { - - LongIntHashMap cloned = (LongIntHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (LongIntCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static LongIntHashMap from(long[] keys, int[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - LongIntHashMap map = new LongIntHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(long key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(long[] fromKeys, int[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final long[] keys = this.keys; - final int[] values = this.values; - final int mask = this.mask; - long existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - long[] prevKeys = this.keys; - int[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new long[arraySize + emptyElementSlot]); - this.values = (new int[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, long pendingKey, int pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final long[] prevKeys = this.keys; - final int[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final long[] keys = this.keys; - final int[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final long existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0L; - values[gapSlot] = 0; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongIntMap.java b/sources/main/java/com/carrotsearch/hppc/LongIntMap.java deleted file mode 100644 index 6fb8c866..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongIntMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongIntCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface LongIntMap extends LongIntAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public int get(long key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public int getOrDefault(long key, int defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public int put(long key, int value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(long key, int value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(LongIntAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public int putOrAdd(long key, int putValue, int incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public int addTo(long key, int additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public int remove(long key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link LongIntMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(long key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexReplace(int index, int newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, long key, int value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongLongAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/LongLongAssociativeContainer.java deleted file mode 100644 index 24be1a2e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongLongAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see LongContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface LongLongAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(long key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongLongPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongLongProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongLongPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public LongCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public LongContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongLongHashMap.java b/sources/main/java/com/carrotsearch/hppc/LongLongHashMap.java deleted file mode 100644 index c1937803..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongLongHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of long to long, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class LongLongHashMap implements LongLongMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public long[] keys; - - /** The array holding values. */ - public long[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public LongLongHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongLongHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public LongLongHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public LongLongHashMap(LongLongAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public long put(long key, long value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - long previousValue = hasEmptyKey ? values[mask + 1] : 0L; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final long previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(LongLongAssociativeContainer container) { - final int count = size(); - for (LongLongCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (LongLongCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public long putOrAdd(long key, long putValue, long incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((long) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public long addTo(long key, long incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public long remove(long key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0L; - } - hasEmptyKey = false; - long previousValue = values[mask + 1]; - values[mask + 1] = 0L; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final long previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof LongLookupContainer) { - if (hasEmptyKey && other.contains(0L)) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (LongCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongLongPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0L, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - } - - final long[] keys = this.keys; - final long[] values = this.values; - for (int slot = 0; slot <= mask; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0L)) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public long get(long key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0L; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public long getOrDefault(long key, long defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(long key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(long key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public long indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public long indexReplace(int index, long newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - long previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, long key, long value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public long indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - long previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0L; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0L); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (LongLongCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(LongLongHashMap other) { - if (other.size() != size()) { - return false; - } - - for (LongLongCursor c : other) { - long key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final long[] prevKeys = this.keys; - final long[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongLongCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new LongLongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongLongCursor fetch() { - final int mask = LongLongHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0L; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final long[] keys = this.keys; - final long[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0L, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final long[] keys = this.keys; - final long[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0L, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final LongLongHashMap owner = LongLongHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongLongProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongLongPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(LongPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final long e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = LongLongHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0L; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public LongCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractLongCollection { - private final LongLongHashMap owner = LongLongHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(long value) { - for (LongLongCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (LongLongCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (LongLongCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final long e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final LongPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = LongLongHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public LongLongHashMap clone() { - try { - - LongLongHashMap cloned = (LongLongHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (LongLongCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static LongLongHashMap from(long[] keys, long[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - LongLongHashMap map = new LongLongHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(long key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(long[] fromKeys, long[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final long[] keys = this.keys; - final long[] values = this.values; - final int mask = this.mask; - long existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - long[] prevKeys = this.keys; - long[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new long[arraySize + emptyElementSlot]); - this.values = (new long[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, long pendingKey, long pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final long[] prevKeys = this.keys; - final long[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final long[] keys = this.keys; - final long[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final long existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0L; - values[gapSlot] = 0L; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongLongMap.java b/sources/main/java/com/carrotsearch/hppc/LongLongMap.java deleted file mode 100644 index 3ea093c9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongLongMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongLongCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface LongLongMap extends LongLongAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public long get(long key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public long getOrDefault(long key, long defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public long put(long key, long value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(long key, long value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(LongLongAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public long putOrAdd(long key, long putValue, long incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public long addTo(long key, long additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public long remove(long key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link LongLongMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(long key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexReplace(int index, long newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, long key, long value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongLookupContainer.java b/sources/main/java/com/carrotsearch/hppc/LongLookupContainer.java deleted file mode 100644 index 70a99942..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongLookupContainer.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Marker interface for containers that can check if they contain a given object in at least time - * O(log n) and ideally in amortized constant time O(1). - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeLookupContainer.java") -public interface LongLookupContainer extends LongContainer { - public boolean contains(long e); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongObjectAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/LongObjectAssociativeContainer.java deleted file mode 100644 index 9e805ffc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongObjectAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see LongContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface LongObjectAssociativeContainer extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(long key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongObjectPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongObjectProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongObjectPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public LongCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ObjectContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongObjectHashMap.java b/sources/main/java/com/carrotsearch/hppc/LongObjectHashMap.java deleted file mode 100644 index e8647afd..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongObjectHashMap.java +++ /dev/null @@ -1,1050 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of long to Object, implemented using open addressing with - * linear probing for collision resolution. Supports null values. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class LongObjectHashMap - implements LongObjectMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public long[] keys; - - /** The array holding values. */ - public Object[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public LongObjectHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongObjectHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public LongObjectHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public LongObjectHashMap(LongObjectAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public VType put(long key, VType value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - VType previousValue = hasEmptyKey ? (VType) values[mask + 1] : null; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final VType previousValue = (VType) values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return null; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(LongObjectAssociativeContainer container) { - final int count = size(); - for (LongObjectCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (LongObjectCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** {@inheritDoc} */ - @Override - public VType remove(long key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return null; - } - hasEmptyKey = false; - VType previousValue = (VType) values[mask + 1]; - values[mask + 1] = null; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final VType previousValue = (VType) values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return null; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof LongLookupContainer) { - if (hasEmptyKey && other.contains(0L)) { - hasEmptyKey = false; - values[mask + 1] = null; - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (LongCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongObjectPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0L, (VType) values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = null; - } - } - - final long[] keys = this.keys; - final VType[] values = (VType[]) this.values; - for (int slot = 0; slot <= mask; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0L)) { - hasEmptyKey = false; - values[mask + 1] = null; - } - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public VType get(long key) { - if (((key) == 0)) { - return hasEmptyKey ? (VType) values[mask + 1] : null; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return (VType) values[slot]; - } - slot = (slot + 1) & mask; - } - - return null; - } - } - - /** {@inheritDoc} */ - @Override - public VType getOrDefault(long key, VType defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? (VType) values[mask + 1] : defaultValue; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return (VType) values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(long key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(long key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public VType indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return (VType) values[index]; - } - - /** {@inheritDoc} */ - @Override - public VType indexReplace(int index, VType newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - VType previousValue = (VType) values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, long key, VType value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public VType indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - VType previousValue = (VType) values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = null; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0L); - - Arrays.fill(values, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (LongObjectCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Values are compared - * using {@link Objects#equals(Object)} method. - */ - protected boolean equalElements(LongObjectHashMap other) { - if (other.size() != size()) { - return false; - } - - for (LongObjectCursor c : other) { - long key = c.key; - if (!containsKey(key) || !java.util.Objects.equals(c.value, get(key))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final long[] prevKeys = this.keys; - final VType[] prevValues = (VType[]) this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final LongObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new LongObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongObjectCursor fetch() { - final int mask = LongObjectHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = (VType) values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0L; - cursor.value = (VType) values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final long[] keys = this.keys; - final VType[] values = (VType[]) this.values; - - if (hasEmptyKey) { - procedure.apply(0L, (VType) values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final long[] keys = this.keys; - final VType[] values = (VType[]) this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0L, (VType) values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final LongObjectHashMap owner = LongObjectHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongObjectProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongObjectPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(LongPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final long e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = LongObjectHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0L; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ObjectCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractObjectCollection { - private final LongObjectHashMap owner = LongObjectHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(VType value) { - for (LongObjectCursor c : owner) { - if (java.util.Objects.equals(value, c.value)) { - return true; - } - } - return false; - } - - @Override - public > T forEach(T procedure) { - for (LongObjectCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - for (LongObjectCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator> iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final VType e) { - return owner.removeAll((key, value) -> java.util.Objects.equals(e, value)); - } - - @Override - public int removeAll(final ObjectPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = LongObjectHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = (VType) values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = (VType) values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public LongObjectHashMap clone() { - try { - - LongObjectHashMap cloned = (LongObjectHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (LongObjectCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static LongObjectHashMap from(long[] keys, VType[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - LongObjectHashMap map = new LongObjectHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(long key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(long[] fromKeys, VType[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final long[] keys = this.keys; - final VType[] values = (VType[]) this.values; - final int mask = this.mask; - long existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - long[] prevKeys = this.keys; - VType[] prevValues = (VType[]) this.values; - try { - int emptyElementSlot = 1; - this.keys = (new long[arraySize + emptyElementSlot]); - this.values = ((VType[]) new Object[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, long pendingKey, VType pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final long[] prevKeys = this.keys; - final VType[] prevValues = (VType[]) this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final long[] keys = this.keys; - final VType[] values = (VType[]) this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final long existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0L; - values[gapSlot] = null; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongObjectMap.java b/sources/main/java/com/carrotsearch/hppc/LongObjectMap.java deleted file mode 100644 index 712d01a5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongObjectMap.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongObjectCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface LongObjectMap extends LongObjectAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public VType get(long key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public VType getOrDefault(long key, VType defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public VType put(long key, VType value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(long key, VType value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(LongObjectAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public VType remove(long key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link LongObjectMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(long key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexReplace(int index, VType newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, long key, VType value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongPgmIndex.java b/sources/main/java/com/carrotsearch/hppc/LongPgmIndex.java deleted file mode 100644 index dc80b159..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongPgmIndex.java +++ /dev/null @@ -1,600 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongCursor; -import com.carrotsearch.hppc.procedures.LongProcedure; -import java.util.Arrays; -import java.util.Iterator; - -/** - * Space-efficient index that enables fast rank/range search operations on a sorted sequence of - * long. - * - *

Implementation of the PGM-Index described at https://pgm.di.unipi.it/, based on the paper - * - *

- *   Paolo Ferragina and Giorgio Vinciguerra.
- *   The PGM-index: a fully-dynamic compressed learned index with provable worst-case bounds.
- *   PVLDB, 13(8): 1162-1175, 2020.
- * 
- * - * It provides {@code rank} and {@code range} search operations. {@code indexOf()} is faster than - * B+Tree, and the index is much more compact. {@code contains()} is between 4x to 7x slower than - * {@code IntHashSet#contains()}, but between 2.5x to 3x faster than {@link Arrays#binarySearch}. - * - *

Its compactness (40KB for 200MB of keys) makes it efficient for very large collections, the - * index fitting easily in the L2 cache. The {@code epsilon} parameter should be set according to - * the desired space-time trade-off. A smaller value makes the estimation more precise and the range - * smaller but at the cost of increased space usage. In practice, {@code epsilon} 64 is a good sweet - * spot. - * - *

Internally the index uses an optimal piecewise linear mapping from keys to their position in - * the sorted order. This mapping is represented as a sequence of linear models (segments) which are - * themselves recursively indexed by other piecewise linear mappings. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypePgmIndex.java") -public class LongPgmIndex implements Accountable { - - /** Empty immutable LongPgmIndex. */ - public static final LongPgmIndex EMPTY = new LongEmptyPgmIndex(); - - /** - * Epsilon approximation range when searching the list of keys. Controls the size of the returned - * search range, strictly greater than 0. It should be set according to the desired space-time - * trade-off. A smaller value makes the estimation more precise and the range smaller but at the - * cost of increased space usage. - * - *

With EPSILON=64 the benchmark with 200MB of keys shows that this PGM index requires only 2% - * additional memory on average (40KB). It depends on the distribution of the keys. This epsilon - * value is good even for 2MB of keys. With EPSILON=32: +5% speed, but 4x space (160KB). - */ - public static final int EPSILON = 64; - - /** - * Epsilon approximation range for the segments layers. Controls the size of the search range in - * the hierarchical segment lists, strictly greater than 0. - */ - public static final int EPSILON_RECURSIVE = 32; - - /** Size of a key, measured in {@link Integer#BYTES} because the key is stored in an int[]. */ - public static final int KEY_SIZE = - RamUsageEstimator.primitiveSizes.get(long.class) / Integer.BYTES; - - /** 2x {@link #KEY_SIZE}. */ - public static final int DOUBLE_KEY_SIZE = KEY_SIZE * 2; - - /** - * Data size of a segment, measured in {@link Integer#BYTES}, because segments are stored in an - * int[]. - */ - public static final int SEGMENT_DATA_SIZE = KEY_SIZE * 3; - - /** Initial value of the exponential jump when scanning out of the epsilon range. */ - public static final int BEYOND_EPSILON_JUMP = 16; - - /** - * The list of keys for which this index is built. It is sorted and may contain duplicate - * elements. - */ - public final LongArrayList keys; - - /** The size of the key set. That is, the number of distinct elements in {@link #keys}. */ - public final int size; - - /** The lowest key in {@link #keys}. */ - public final long firstKey; - - /** The highest key in {@link #keys}. */ - public final long lastKey; - - /** The epsilon range used to build this index. */ - public final int epsilon; - - /** The recursive epsilon range used to build this index. */ - public final int epsilonRecursive; - - /** The offsets in {@link #segmentData} of the first segment of each segment level. */ - public final int[] levelOffsets; - - /** The index data. It contains all the segments for all the levels. */ - public final int[] segmentData; - - private LongPgmIndex( - LongArrayList keys, - int size, - int epsilon, - int epsilonRecursive, - int[] levelOffsets, - int[] segmentData) { - assert keys.size() > 0; - assert size > 0 && size <= keys.size(); - assert epsilon > 0; - assert epsilonRecursive > 0; - this.keys = keys; - this.size = size; - firstKey = keys.get(0); - lastKey = keys.get(keys.size() - 1); - this.epsilon = epsilon; - this.epsilonRecursive = epsilonRecursive; - this.levelOffsets = levelOffsets; - this.segmentData = segmentData; - } - - /** Empty set constructor. */ - private LongPgmIndex() { - keys = new LongArrayList(0); - size = 0; - firstKey = 0L; - lastKey = 0L; - epsilon = 0; - epsilonRecursive = 0; - levelOffsets = new int[0]; - segmentData = levelOffsets; - } - - /** Returns the size of the key set. That is, the number of distinct elements in {@link #keys}. */ - public int size() { - return size; - } - - /** Returns whether this key set is empty. */ - public boolean isEmpty() { - return size() == 0; - } - - /** Returns whether this key set contains the given key. */ - public boolean contains(long key) { - return indexOf(key) >= 0; - } - - /** - * Searches the specified key, and returns its index in the element list. If multiple elements are - * equal to the specified key, there is no guarantee which one will be found. - * - * @return The index of the searched key if it is present; otherwise, {@code (-(insertion - * point) - 1)}. The insertion point is defined as the point at which the key would - * be inserted into the list: the index of the first element greater than the key, or {@link - * #keys}#{@code size()} if all the elements are less than the specified key. Note that this - * guarantees that the return value will be >= 0 if and only if the key is found. - */ - public int indexOf(long key) { - if (key < firstKey) { - return -1; - } - if (key > lastKey) { - return -keys.size() - 1; - } - final int[] segmentData = this.segmentData; - int segmentDataIndex = findSegment(key); - int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); - int index = - Math.min( - approximateIndex(key, segmentDataIndex, segmentData), - Math.min(nextIntercept, keys.size() - 1)); - assert index >= 0 && index < keys.size(); - long k = keys.get(index); - if (key < k) { - // Scan sequentially before the approximated index, within epsilon range. - final int fromIndex = Math.max(index - epsilon - 1, 0); - while (--index >= fromIndex) { - k = keys.get(index); - if (key > k) { - return -index - 2; - } - if (((key) == (k))) { - return index; - } - } - // Continue scanning out of the epsilon range. - // This might happen in rare cases of precision error during the approximation - // computation for longs (we don't have long double 128 bits in Java). - // This might also happen in rare corner cases of large duplicate elements - // sequence at the epsilon range boundary. - index++; - int jump = BEYOND_EPSILON_JUMP; - do { - int loIndex = Math.max(index - jump, 0); - if (key >= keys.get(loIndex)) { - return Arrays.binarySearch(keys.buffer, loIndex, index, key); - } - index = loIndex; - jump <<= 1; - } while (index > 0); - return -1; - } else if (((key) == (k))) { - return index; - } else { - // Scan sequentially after the approximated index, within epsilon range. - final int toIndex = Math.min(index + epsilon + 3, keys.size()); - while (++index < toIndex) { - k = keys.get(index); - if (key < k) { - return -index - 1; - } - if (((key) == (k))) { - return index; - } - } - // Continue scanning out of the epsilon range. - int jump = BEYOND_EPSILON_JUMP; - do { - int hiIndex = Math.min(index + jump, keys.size()); - if (key <= keys.get(hiIndex)) { - return Arrays.binarySearch(keys.buffer, index, hiIndex, key); - } - index = hiIndex; - jump <<= 1; - } while (index < keys.size()); - return -keys.size() - 1; - } - } - - /** - * Returns, for any value {@code x}, the number of keys in the sorted list which are smaller than - * {@code x}. It is equal to {@link #indexOf} if {@code x} belongs to the list, or -{@link - * #indexOf}-1 otherwise. - * - *

If multiple elements are equal to the specified key, there is no guarantee which one will be - * found. - * - * @return The index of the searched key if it is present; otherwise, the {@code insertion point}. - * The insertion point is defined as the point at which the key would be inserted into - * the list: the index of the first element greater than the key, or {@link #keys}#{@code - * size()} if all the elements are less than the specified key. Note that this method always - * returns a value >= 0. - */ - public int rank(long x) { - int index = indexOf(x); - return index >= 0 ? index : -index - 1; - } - - /** - * Returns the number of keys in the list that are greater than or equal to {@code minKey} - * (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public int rangeCardinality(long minKey, long maxKey) { - int fromIndex = rank(minKey); - int maxIndex = indexOf(maxKey); - int toIndex = maxIndex >= 0 ? maxIndex + 1 : -maxIndex - 1; - return Math.max(toIndex - fromIndex, 0); - } - - /** - * Returns an iterator over the keys in the list that are greater than or equal to {@code minKey} - * (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public Iterator rangeIterator(long minKey, long maxKey) { - int fromIndex = rank(minKey); - return new RangeIterator(keys, fromIndex, maxKey); - } - - /** - * Applies {@code procedure} to the keys in the list that are greater than or equal to {@code - * minKey} (inclusive), and less than or equal to {@code maxKey} (inclusive). - */ - public T forEachInRange(T procedure, long minKey, long maxKey) { - final long[] buffer = keys.buffer; - long k; - for (int i = rank(minKey), size = keys.size(); i < size && (k = buffer[i]) <= maxKey; i++) { - procedure.apply(k); - } - return procedure; - } - - /** - * Estimates the allocated memory. It does not count the memory for the list of keys, only for the - * index itself. - */ - @Override - public long ramBytesAllocated() { - // int: size, epsilon, epsilonRecursive - // long: firstKey, lastKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 3 * Integer.BYTES - + 2L * KEY_SIZE * Integer.BYTES - // + keys.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(levelOffsets) - + RamUsageEstimator.shallowSizeOfArray(segmentData); - } - - /** - * Estimates the bytes that are actually used. It does not count the memory for the list of keys, - * only for the index itself. - */ - @Override - public long ramBytesUsed() { - // int: size, epsilon, epsilonRecursive - // long: firstKey, lastKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 3 * Integer.BYTES - + 2L * KEY_SIZE * Integer.BYTES - // + keys.ramBytesUsed() - + RamUsageEstimator.shallowSizeOfArray(levelOffsets) - + RamUsageEstimator.shallowSizeOfArray(segmentData); - } - - /** - * Finds the segment responsible for a given key, that is, the rightmost segment having its first - * key <= the searched key. - * - * @return the segment data index; or -1 if none. - */ - private int findSegment(long key) { - assert key >= firstKey && key <= lastKey; - final int epsilonRecursive = this.epsilonRecursive; - final int[] levelOffsets = this.levelOffsets; - final int[] segmentData = this.segmentData; - int level = levelOffsets.length - 1; - int segmentDataIndex = levelOffsets[level] * SEGMENT_DATA_SIZE; - while (--level >= 0) { - int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); - int index = Math.min(approximateIndex(key, segmentDataIndex, segmentData), nextIntercept); - assert index >= 0 && index <= levelOffsets[level + 1] - levelOffsets[level] - 1; - int sdIndex = (levelOffsets[level] + index) * SEGMENT_DATA_SIZE; - if (getKey(sdIndex, segmentData) <= key) { - // Scan sequentially segments after the approximated index, within the epsilon range. - final int levelNumSegments = levelOffsets[level + 1] - levelOffsets[level] - 1; - final int toIndex = Math.min(index + epsilonRecursive + 3, levelNumSegments); - while (index++ < toIndex && getKey(sdIndex + SEGMENT_DATA_SIZE, segmentData) <= key) { - sdIndex += SEGMENT_DATA_SIZE; - } - } else { - // Scan sequentially segments before the approximated index, within the epsilon range. - final int fromIndex = Math.max(index - epsilonRecursive - 1, 0); - while (index-- > fromIndex) { - sdIndex -= SEGMENT_DATA_SIZE; - if (getKey(sdIndex, segmentData) <= key) { - break; - } - } - } - segmentDataIndex = sdIndex; - } - assert segmentDataIndex >= 0; - return segmentDataIndex; - } - - private int approximateIndex(long key, int segmentDataIndex, int[] segmentData) { - long intercept = getIntercept(segmentDataIndex, segmentData); - long sKey = getKey(segmentDataIndex, segmentData); - double slope = getSlope(segmentDataIndex, segmentData); - int index = (int) (slope * ((double) key - sKey) + intercept); - return Math.max(index, 0); - } - - private static long getIntercept(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getIntercept(segmentDataIndex, segmentData, KEY_SIZE); - } - - private long getKey(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0L); - } - - private static double getSlope(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getSlope(segmentDataIndex + DOUBLE_KEY_SIZE, segmentData, KEY_SIZE); - } - - /** Empty immutable PGM Index. */ - private static class LongEmptyPgmIndex extends LongPgmIndex { - - private final Iterator emptyIterator = new LongEmptyIterator(); - - @Override - public int indexOf(long key) { - return -1; - } - - @Override - public Iterator rangeIterator(long minKey, long maxKey) { - return emptyIterator; - } - - @Override - public T forEachInRange(T procedure, long minKey, long maxKey) { - return procedure; - } - - private static class LongEmptyIterator extends AbstractIterator { - @Override - protected LongCursor fetch() { - return done(); - } - } - } - - /** Iterator over a range of elements in a sorted array. */ - protected static class RangeIterator extends AbstractIterator { - private final long[] buffer; - private final int size; - private final LongCursor cursor; - private final long maxKey; - - /** Range iterator from {@code fromIndex} (inclusive) to {@code maxKey} (inclusive). */ - protected RangeIterator(LongArrayList keys, int fromIndex, long maxKey) { - this.buffer = keys.buffer; - this.size = keys.size(); - this.cursor = new LongCursor(); - this.cursor.index = fromIndex; - this.maxKey = maxKey; - } - - @Override - protected LongCursor fetch() { - if (cursor.index >= size) { - return done(); - } - cursor.value = buffer[cursor.index++]; - if (cursor.value > maxKey) { - cursor.index = size; - return done(); - } - return cursor; - } - } - - /** Builds a {@link LongPgmIndex} on a provided sorted list of keys. */ - public static class LongBuilder implements PlaModel.SegmentConsumer, Accountable { - - protected LongArrayList keys; - protected int epsilon = EPSILON; - protected int epsilonRecursive = EPSILON_RECURSIVE; - protected PlaModel plam; - protected int size; - protected IntArrayList segmentData; - protected int numSegments; - - /** Sets the sorted list of keys to build the index for; duplicate elements are allowed. */ - public LongBuilder setSortedKeys(LongArrayList keys) { - this.keys = keys; - return this; - } - - /** Sets the sorted array of keys to build the index for; duplicate elements are allowed. */ - public LongBuilder setSortedKeys(long[] keys, int length) { - LongArrayList keyList = new LongArrayList(0); - keyList.buffer = keys; - keyList.elementsCount = length; - return setSortedKeys(keyList); - } - - /** Sets the epsilon range to use when learning the segments for the list of keys. */ - public LongBuilder setEpsilon(int epsilon) { - if (epsilon <= 0) { - throw new IllegalArgumentException("epsilon must be > 0"); - } - this.epsilon = epsilon; - return this; - } - - /** - * Sets the recursive epsilon range to use when learning the segments for the segment levels. - */ - public LongBuilder setEpsilonRecursive(int epsilonRecursive) { - if (epsilonRecursive <= 0) { - throw new IllegalArgumentException("epsilonRecursive must be > 0"); - } - this.epsilonRecursive = epsilonRecursive; - return this; - } - - /** Builds the {@link LongPgmIndex}; or {@link #EMPTY} if there are no keys in the list. */ - public LongPgmIndex build() { - if (keys == null || keys.size() == 0) { - return (LongPgmIndex) EMPTY; - } - plam = new PlaModel(epsilon); - - int segmentsInitialCapacity = - Math.min( - Math.max(keys.size() / (2 * epsilon * epsilon) * SEGMENT_DATA_SIZE, 16), 1 << 19); - segmentData = new IntArrayList(segmentsInitialCapacity); - IntArrayList levelOffsets = new IntArrayList(16); - - int levelOffset = 0; - levelOffsets.add(levelOffset); - int levelNumSegments = buildFirstLevel(); - while (levelNumSegments > 1) { - int nextLevelOffset = numSegments; - levelOffsets.add(nextLevelOffset); - levelNumSegments = buildUpperLevel(levelOffset, levelNumSegments); - levelOffset = nextLevelOffset; - } - - int[] segmentDataFinal = segmentData.toArray(); - int[] levelOffsetsFinal = levelOffsets.toArray(); - return new LongPgmIndex( - keys, size, epsilon, epsilonRecursive, levelOffsetsFinal, segmentDataFinal); - } - - private int buildFirstLevel() { - assert numSegments == 0; - int numKeys = keys.size(); - int size = 0; - long key = keys.get(0); - size++; - plam.addKey(key, 0, this); - for (int i = 1; i < numKeys; i++) { - long nextKey = keys.get(i); - if (!((nextKey) == (key))) { - key = nextKey; - plam.addKey(key, i, this); - size++; - } - } - plam.finish(this); - addSentinelSegment(numKeys); - this.size = size; - return numSegments - 1; - } - - private int buildUpperLevel(int levelOffset, int levelNumSegments) { - plam.setEpsilon(epsilonRecursive); - assert numSegments > 0; - int initialNumSegments = numSegments; - int segmentDataIndex = levelOffset * SEGMENT_DATA_SIZE; - long key = getKey(segmentDataIndex, segmentData.buffer); - plam.addKey(key, 0, this); - for (int i = 1; i < levelNumSegments; i++) { - segmentDataIndex += SEGMENT_DATA_SIZE; - long nextKey = getKey(segmentDataIndex, segmentData.buffer); - if (!((nextKey) == (key))) { - key = nextKey; - plam.addKey(key, i, this); - } - } - plam.finish(this); - addSentinelSegment(levelNumSegments); - return numSegments - initialNumSegments - 1; - } - - private long getKey(int segmentDataIndex, int[] segmentData) { - return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0L); - } - - /** - * Adds a sentinel segment that is used to give a limit for the position approximation, but does - * not count in the number of segments per level. - */ - private void addSentinelSegment(int endIndex) { - // This sentinel segment is used in findSegment(). - accept(Double.MAX_VALUE, 0d, endIndex); - } - - @Override - public void accept(double firstKey, double slope, long intercept) { - PgmIndexUtil.addIntercept(intercept, segmentData, KEY_SIZE); - PgmIndexUtil.addKey((long) firstKey, segmentData); - PgmIndexUtil.addSlope(slope, segmentData, KEY_SIZE); - numSegments++; - assert segmentData.size() == numSegments * SEGMENT_DATA_SIZE; - } - - /** - * Estimates the allocated memory. It does not count the memory for the list of keys, only for - * the builder itself. - */ - @Override - public long ramBytesAllocated() { - // int: epsilon, epsilonRecursive, size, numSegments - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - // + keys.ramBytesAllocated() - + plam.ramBytesAllocated() - + segmentData.ramBytesAllocated(); - } - - /** - * Estimates the bytes that are actually used. It does not count the memory for the list of - * keys, only for the builder itself. - */ - @Override - public long ramBytesUsed() { - // int: epsilon, epsilonRecursive, size, numSegments - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - // + keys.ramBytesUsed() - + plam.ramBytesUsed() - + segmentData.ramBytesUsed(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongSet.java b/sources/main/java/com/carrotsearch/hppc/LongSet.java deleted file mode 100644 index 69a3144a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongSet.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** A set of longs. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java") -public interface LongSet extends LongCollection { - /** - * Adds k to the set. - * - * @return Returns true if this element was not part of the set before. Returns - * false if an equal element is already part of the set, does not replace the - * existing element with the argument. - */ - public boolean add(long k); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); - - /** - * Adds all elements from the given {@link LongContainer} to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - * @since 0.9.1 - */ - public int addAll(LongContainer container); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongShortAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/LongShortAssociativeContainer.java deleted file mode 100644 index e9f9f677..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongShortAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see LongContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface LongShortAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(long key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(LongShortPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongShortProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link LongShortPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public LongCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ShortContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongShortHashMap.java b/sources/main/java/com/carrotsearch/hppc/LongShortHashMap.java deleted file mode 100644 index cf9a34c8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongShortHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of long to short, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeHashMap.java") -public class LongShortHashMap implements LongShortMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public long[] keys; - - /** The array holding values. */ - public short[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public LongShortHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongShortHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public LongShortHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public LongShortHashMap(LongShortAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public short put(long key, short value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - short previousValue = hasEmptyKey ? values[mask + 1] : ((short) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final short previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(LongShortAssociativeContainer container) { - final int count = size(); - for (LongShortCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (LongShortCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public short putOrAdd(long key, short putValue, short incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((short) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public short addTo(long key, short incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public short remove(long key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((short) 0); - } - hasEmptyKey = false; - short previousValue = values[mask + 1]; - values[mask + 1] = ((short) 0); - return previousValue; - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final short previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof LongLookupContainer) { - if (hasEmptyKey && other.contains(0L)) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (LongCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongShortPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(0L, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - } - - final long[] keys = this.keys; - final short[] values = this.values; - for (int slot = 0; slot <= mask; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(LongPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(0L)) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - } - - final long[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - long existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public short get(long key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((short) 0); - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public short getOrDefault(long key, short defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(long key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final long[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(long key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final long[] keys = this.keys; - int slot = hashKey(key) & mask; - - long existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public short indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public short indexReplace(int index, short newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - short previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, long key, short value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public short indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - short previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((short) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, 0L); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (LongShortCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(LongShortHashMap other) { - if (other.size() != size()) { - return false; - } - - for (LongShortCursor c : other) { - long key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final long[] prevKeys = this.keys; - final short[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new LongShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongShortCursor fetch() { - final int mask = LongShortHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = 0L; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final long[] keys = this.keys; - final short[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(0L, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final long[] keys = this.keys; - final short[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(0L, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final LongShortHashMap owner = LongShortHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongShortProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongShortPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(LongPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final long e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = LongShortHashMap.this.mask; - while (index <= mask) { - long existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = 0L; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ShortCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractShortCollection { - private final LongShortHashMap owner = LongShortHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(short value) { - for (LongShortCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (LongShortCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (LongShortCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final short e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final ShortPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = LongShortHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public LongShortHashMap clone() { - try { - - LongShortHashMap cloned = (LongShortHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (LongShortCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static LongShortHashMap from(long[] keys, short[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - LongShortHashMap map = new LongShortHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(long key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(long[] fromKeys, short[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final long[] keys = this.keys; - final short[] values = this.values; - final int mask = this.mask; - long existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - long[] prevKeys = this.keys; - short[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new long[arraySize + emptyElementSlot]); - this.values = (new short[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, long pendingKey, short pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final long[] prevKeys = this.keys; - final short[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final long[] keys = this.keys; - final short[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final long existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = 0L; - values[gapSlot] = ((short) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongShortMap.java b/sources/main/java/com/carrotsearch/hppc/LongShortMap.java deleted file mode 100644 index 3ef50522..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongShortMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongShortCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface LongShortMap extends LongShortAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public short get(long key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public short getOrDefault(long key, short defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public short put(long key, short value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(long key, short value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(LongShortAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public short putOrAdd(long key, short putValue, short incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public short addTo(long key, short additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public short remove(long key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link LongShortMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(long key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexReplace(int index, short newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, long key, short value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/LongStack.java b/sources/main/java/com/carrotsearch/hppc/LongStack.java deleted file mode 100644 index 6d5f15ff..00000000 --- a/sources/main/java/com/carrotsearch/hppc/LongStack.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.LongCursor; - -/** - * A subclass of {@link LongArrayList} adding stack-related utility methods. The top of the stack is - * at the {@link #size()} - 1 element. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") -public class LongStack extends LongArrayList { - /** New instance with sane defaults. */ - public LongStack() { - super(); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public LongStack(int expectedElements) { - super(expectedElements); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public LongStack(int expectedElements, ArraySizingStrategy resizer) { - super(expectedElements, resizer); - } - - /** Create a stack by pushing all elements of another container to it. */ - public LongStack(LongContainer container) { - super(container); - } - - /** Adds one long to the stack. */ - public void push(long e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** Adds two longs to the stack. */ - public void push(long e1, long e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Adds three longs to the stack. */ - public void push(long e1, long e2, long e3) { - ensureBufferSpace(3); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - } - - /** Adds four longs to the stack. */ - public void push(long e1, long e2, long e3, long e4) { - ensureBufferSpace(4); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - buffer[elementsCount++] = e4; - } - - /** Add a range of array elements to the stack. */ - public void push(long[] elements, int start, int len) { - assert start >= 0 && len >= 0; - - ensureBufferSpace(len); - System.arraycopy(elements, start, buffer, elementsCount, len); - elementsCount += len; - } - - /** - * Vararg-signature method for pushing elements at the top of the stack. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void push(long... elements) { - push(elements, 0, elements.length); - } - - /** Pushes all elements from another container to the top of the stack. */ - public int pushAll(LongContainer container) { - return addAll(container); - } - - /** Pushes all elements from another iterable to the top of the stack. */ - public int pushAll(Iterable iterable) { - return addAll(iterable); - } - - /** Discard an arbitrary number of elements from the top of the stack. */ - public void discard(int count) { - assert elementsCount >= count; - - elementsCount -= count; - } - - /** Discard the top element from the stack. */ - public void discard() { - assert elementsCount > 0; - - elementsCount--; - } - - /** Remove the top element from the stack and return it. */ - public long pop() { - return removeLast(); - } - - /** Peek at the top element on the stack. */ - public long peek() { - assert elementsCount > 0; - return buffer[elementsCount - 1]; - } - - /** Create a stack by pushing a variable number of arguments to it. */ - public static LongStack from(long... elements) { - final LongStack stack = new LongStack(elements.length); - stack.push(elements); - return stack; - } - - /** {@inheritDoc} */ - @Override - public LongStack clone() { - return (LongStack) super.clone(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectArrayDeque.java b/sources/main/java/com/carrotsearch/hppc/ObjectArrayDeque.java deleted file mode 100644 index a25261f8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectArrayDeque.java +++ /dev/null @@ -1,786 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.ObjectCursor; -import com.carrotsearch.hppc.predicates.ObjectPredicate; -import com.carrotsearch.hppc.procedures.ObjectProcedure; -import java.util.*; - -/** An array-backed {@link ObjectDeque}. */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") -public class ObjectArrayDeque extends AbstractObjectCollection - implements ObjectDeque, Preallocable, Cloneable, Accountable { - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** Internal array for storing elements of the deque. */ - public Object[] buffer = ObjectArrayList.EMPTY_ARRAY; - - /** - * The index of the element at the head of the deque or an arbitrary number equal to tail if the - * deque is empty. - */ - public int head; - - /** The index at which the next element would be added to the tail of the deque. */ - public int tail; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public ObjectArrayDeque() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectArrayDeque(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public ObjectArrayDeque(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - ensureCapacity(expectedElements); - } - - /** - * Creates a new deque from elements of another container, appending elements at the end of the - * deque in the iteration order. - */ - public ObjectArrayDeque(ObjectContainer container) { - this(container.size()); - addLast(container); - } - - /** {@inheritDoc} */ - @Override - public void addFirst(KType e1) { - int h = oneLeft(head, buffer.length); - if (h == tail) { - ensureBufferSpace(1); - h = oneLeft(head, buffer.length); - } - buffer[head = h] = e1; - } - - /** - * Vararg-signature method for adding elements at the front of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to add. - */ - @SafeVarargs - public final void addFirst(KType... elements) { - ensureBufferSpace(elements.length); - for (KType k : elements) { - addFirst(k); - } - } - - /** - * Inserts all elements from the given container to the front of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(ObjectContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (ObjectCursor cursor : container) { - addFirst(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the front of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(Iterable> iterable) { - int size = 0; - for (ObjectCursor cursor : iterable) { - addFirst(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void addLast(KType e1) { - int t = oneRight(tail, buffer.length); - if (head == t) { - ensureBufferSpace(1); - t = oneRight(tail, buffer.length); - } - buffer[tail] = e1; - tail = t; - } - - /** - * Vararg-signature method for adding elements at the end of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to iterate over. - */ - @SafeVarargs - public final void addLast(KType... elements) { - ensureBufferSpace(1); - for (KType k : elements) { - addLast(k); - } - } - - /** - * Inserts all elements from the given container to the end of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(ObjectContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (ObjectCursor cursor : container) { - addLast(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the end of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(Iterable> iterable) { - int size = 0; - for (ObjectCursor cursor : iterable) { - addLast(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public KType removeFirst() { - assert size() > 0 : "The deque is empty."; - - final KType result = (KType) buffer[head]; - buffer[head] = null; - head = oneRight(head, buffer.length); - return result; - } - - /** {@inheritDoc} */ - @Override - public KType removeLast() { - assert size() > 0 : "The deque is empty."; - - tail = oneLeft(tail, buffer.length); - final KType result = (KType) buffer[tail]; - buffer[tail] = null; - return result; - } - - /** {@inheritDoc} */ - @Override - public KType getFirst() { - assert size() > 0 : "The deque is empty."; - - return (KType) buffer[head]; - } - - /** {@inheritDoc} */ - @Override - public KType getLast() { - assert size() > 0 : "The deque is empty."; - - return (KType) buffer[oneLeft(tail, buffer.length)]; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(KType e1) { - final int index = bufferIndexOf(e1); - if (index >= 0) removeAtBufferIndex(index); - return index; - } - - /** - * Return the index of the first (counting from head) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int bufferIndexOf(KType e1) { - final int last = tail; - final int bufLen = buffer.length; - for (int i = head; i != last; i = oneRight(i, bufLen)) { - if (this.equals(e1, buffer[i])) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(KType e1) { - final int index = lastBufferIndexOf(e1); - if (index >= 0) { - removeAtBufferIndex(index); - } - return index; - } - - /** - * Return the index of the last (counting from tail) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int lastBufferIndexOf(KType e1) { - final int bufLen = buffer.length; - final int last = oneLeft(head, bufLen); - for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { - if (this.equals(e1, buffer[i])) return i; - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(KType e1) { - int removed = 0; - final int last = tail; - final int bufLen = buffer.length; - int from, to; - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (this.equals(e1, buffer[from])) { - buffer[from] = null; - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = null; - } - - to = oneRight(to, bufLen); - } - - tail = to; - return removed; - } - - /** - * Removes the element at index in the internal {#link {@link #buffer} array, - * returning its value. - * - * @param index Index of the element to remove. The index must be located between {@link #head} - * and {@link #tail} in modulo {@link #buffer} arithmetic. - */ - public void removeAtBufferIndex(int index) { - assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) - : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; - - // Cache fields in locals (hopefully moved to registers). - final KType[] buffer = (KType[]) this.buffer; - final int bufLen = buffer.length; - final int lastIndex = bufLen - 1; - final int head = this.head; - final int tail = this.tail; - - final int leftChunk = Math.abs(index - head) % bufLen; - final int rightChunk = Math.abs(tail - index) % bufLen; - - if (leftChunk < rightChunk) { - if (index >= head) { - System.arraycopy(buffer, head, buffer, head + 1, leftChunk); - } else { - System.arraycopy(buffer, 0, buffer, 1, index); - buffer[0] = buffer[lastIndex]; - System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); - } - buffer[head] = null; - this.head = oneRight(head, bufLen); - } else { - if (index < tail) { - System.arraycopy(buffer, index + 1, buffer, index, rightChunk); - } else { - System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); - buffer[lastIndex] = buffer[0]; - System.arraycopy(buffer, 1, buffer, 0, tail); - } - buffer[tail] = null; - this.tail = oneLeft(tail, bufLen); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int size() { - if (head <= tail) return tail - head; - else return (tail - head + buffer.length); - } - - /** - * {@inheritDoc} - * - *

The internal array buffers are not released as a result of this call. - * - * @see #release() - */ - @Override - public void clear() { - if (head < tail) { - Arrays.fill(buffer, head, tail, null); - } else { - Arrays.fill(buffer, 0, tail, null); - Arrays.fill(buffer, head, buffer.length, null); - } - this.head = tail = 0; - } - - /** Release internal buffers of this deque and reallocate with the default buffer. */ - public void release() { - this.head = tail = 0; - buffer = ObjectArrayList.EMPTY_ARRAY; - ensureBufferSpace(0); - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - ensureBufferSpace(expectedElements - size()); - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = buffer.length; - final int elementsCount = size(); - - if (elementsCount + expectedAdditions >= bufferLen) { - final int emptySlot = 1; // deque invariant: always an empty slot. - final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); - assert newSize >= (elementsCount + expectedAdditions + emptySlot) - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - try { - final KType[] newBuffer = ((KType[]) new Object[newSize]); - if (bufferLen > 0) { - toArray(newBuffer); - tail = elementsCount; - head = 0; - } - this.buffer = newBuffer; - } catch (OutOfMemoryError e) { - throw new BufferAllocationException( - "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); - } - } - } - - /** {@inheritDoc} */ - @Override - public Object[] toArray() { - - final int size = size(); - return toArray(((KType[]) new Object[size])); - } - - /** - * Copies elements of this deque to an array. The content of the target array is - * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). - * - * @param target The target array must be large enough to hold all elements. - * @return Returns the target argument for chaining. - */ - public KType[] toArray(KType[] target) { - assert target.length >= size() : "Target array must be >= " + size(); - - if (head < tail) { - // The contents is not wrapped around. Just copy. - System.arraycopy(buffer, head, target, 0, size()); - } else if (head > tail) { - // The contents is split. Merge elements from the following indexes: - // [head...buffer.length - 1][0, tail - 1] - final int rightCount = buffer.length - head; - System.arraycopy(buffer, head, target, 0, rightCount); - System.arraycopy(buffer, 0, target, rightCount, tail); - } - - return target; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public ObjectArrayDeque clone() { - try { - - ObjectArrayDeque cloned = (ObjectArrayDeque) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Move one index to the left, wrapping around buffer. */ - protected static int oneLeft(int index, int modulus) { - if (index >= 1) { - return index - 1; - } - return modulus - 1; - } - - /** Move one index to the right, wrapping around buffer. */ - protected static int oneRight(int index, int modulus) { - if (index + 1 == modulus) { - return 0; - } - return index + 1; - } - - @Override - public long ramBytesAllocated() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); - } - - /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ - private final class ValueIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private int remaining; - - public ValueIterator() { - cursor = new ObjectCursor(); - cursor.index = oneLeft(head, buffer.length); - this.remaining = size(); - } - - @Override - protected ObjectCursor fetch() { - if (remaining == 0) { - return done(); - } - - remaining--; - cursor.value = (KType) buffer[cursor.index = oneRight(cursor.index, buffer.length)]; - return cursor; - } - } - - /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ - private final class DescendingValueIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private int remaining; - - public DescendingValueIterator() { - cursor = new ObjectCursor(); - cursor.index = tail; - this.remaining = size(); - } - - @Override - protected ObjectCursor fetch() { - if (remaining == 0) return done(); - - remaining--; - cursor.value = (KType) buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; - return cursor; - } - } - - /** - * Returns a cursor over the values of this deque (in head to tail order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *

-   * for (IntValueCursor c : intDeque) {
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator> iterator() { - return new ValueIterator(); - } - - /** - * Returns a cursor over the values of this deque (in tail to head order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *
-   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
-   *   final IntCursor c = i.next();
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator> descendingIterator() { - return new DescendingValueIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - forEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, fromIndex, inclusive, to - * toIndex, exclusive. - */ - private void forEach(ObjectProcedure procedure, int fromIndex, final int toIndex) { - final KType[] buffer = (KType[]) this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - procedure.apply(buffer[i]); - } - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - int fromIndex = head; - int toIndex = tail; - - final KType[] buffer = (KType[]) this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (!predicate.apply(buffer[i])) { - break; - } - } - - return predicate; - } - - /** Applies procedure to all elements of this deque, tail to head. */ - @Override - public > T descendingForEach(T procedure) { - descendingForEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive. - */ - private void descendingForEach( - ObjectProcedure procedure, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final KType[] buffer = (KType[]) this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - procedure.apply(buffer[i]); - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public > T descendingForEach(T predicate) { - descendingForEach(predicate, head, tail); - return predicate; - } - - /** - * Applies predicate to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive or until the predicate returns false. - */ - private void descendingForEach( - ObjectPredicate predicate, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final KType[] buffer = (KType[]) this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - if (!predicate.apply(buffer[i])) { - break; - } - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - final KType[] buffer = (KType[]) this.buffer; - final int last = tail; - final int bufLen = buffer.length; - int removed = 0; - int from, to; - from = to = head; - try { - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (predicate.apply(buffer[from])) { - buffer[from] = null; - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = null; - } - - to = oneRight(to, bufLen); - } - } finally { - // Keep the deque in consistent state even if the predicate throws an exception. - for (; from != last; from = oneRight(from, bufLen)) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = null; - } - - to = oneRight(to, bufLen); - } - tail = to; - } - - return removed; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(KType e) { - int fromIndex = head; - int toIndex = tail; - - final KType[] buffer = (KType[]) this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (this.equals(e, buffer[i])) { - return true; - } - } - - return false; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1; - int fromIndex = head; - int toIndex = tail; - - final KType[] buffer = (KType[]) this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. Equality comparison is performed with this object's {@link #equals(Object, - * Object)} method. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Compare order-aligned elements against another {@link ObjectDeque}. Equality comparison is - * performed with this object's {@link #equals(Object, Object)} method. - */ - protected boolean equalElements(ObjectArrayDeque other) { - int max = size(); - if (other.size() != max) { - return false; - } - - Iterator> i1 = this.iterator(); - Iterator> i2 = other.iterator(); - - while (i1.hasNext() && i2.hasNext()) { - if (!this.equals(i1.next().value, i2.next().value)) { - return false; - } - } - - return !i1.hasNext() && !i2.hasNext(); - } - - /** Create a new deque by pushing a variable number of arguments to the end of it. */ - @SafeVarargs - public static ObjectArrayDeque from(KType... elements) { - final ObjectArrayDeque coll = new ObjectArrayDeque(elements.length); - coll.addLast(elements); - return coll; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectArrayList.java b/sources/main/java/com/carrotsearch/hppc/ObjectArrayList.java deleted file mode 100644 index e11da848..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectArrayList.java +++ /dev/null @@ -1,604 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.ObjectPredicate; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; -import java.util.stream.Stream; - -/** An array-backed list of Objects. */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") -public class ObjectArrayList extends AbstractObjectCollection - implements ObjectIndexedContainer, Preallocable, Cloneable, Accountable { - /** An immutable empty buffer (array). */ - public static final Object[] EMPTY_ARRAY = new Object[0]; - - ; - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** - * Internal array for storing the list. The array may be larger than the current size ({@link - * #size()}). - */ - public Object[] buffer = EMPTY_ARRAY; - - /** Current number of elements stored in {@link #buffer}. */ - public int elementsCount; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public ObjectArrayList() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectArrayList(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public ObjectArrayList(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - buffer = Arrays.copyOf(buffer, expectedElements); - } - - /** Creates a new list from the elements of another container in its iteration order. */ - public ObjectArrayList(ObjectContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public void add(KType e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** - * Appends two elements at the end of the list. To add more than two elements, use add - * (vararg-version) or access the buffer directly (tight loop). - */ - public void add(KType e1, KType e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Add all elements from a range of given array to the list. */ - public void add(KType[] elements, int start, int length) { - assert length >= 0 : "Length must be >= 0"; - - ensureBufferSpace(length); - System.arraycopy(elements, start, buffer, elementsCount, length); - elementsCount += length; - } - - /** - * Vararg-signature method for adding elements at the end of the list. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - @SafeVarargs - public final void add(KType... elements) { - add(elements, 0, elements.length); - } - - /** Adds all elements from another container. */ - public int addAll(ObjectContainer container) { - final int size = container.size(); - ensureBufferSpace(size); - - for (ObjectCursor cursor : container) { - add(cursor.value); - } - - return size; - } - - /** Adds all elements from another iterable. */ - public int addAll(Iterable> iterable) { - int size = 0; - for (ObjectCursor cursor : iterable) { - add(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void insert(int index, KType e1) { - assert (index >= 0 && index <= size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; - - ensureBufferSpace(1); - System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); - buffer[index] = e1; - elementsCount++; - } - - /** {@inheritDoc} */ - @Override - public KType get(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - return (KType) buffer[index]; - } - - /** {@inheritDoc} */ - @Override - public KType set(int index, KType e1) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final KType v = (KType) buffer[index]; - buffer[index] = e1; - return v; - } - - /** {@inheritDoc} */ - @Override - public KType removeAt(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final KType v = (KType) buffer[index]; - System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); - - buffer[elementsCount] = null; - - return v; - } - - /** {@inheritDoc} */ - @Override - public KType removeLast() { - assert elementsCount > 0; - - final KType v = (KType) buffer[--elementsCount]; - - buffer[elementsCount] = null; - - return v; - } - - /** {@inheritDoc} */ - @Override - public void removeRange(int fromIndex, int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); - final int count = toIndex - fromIndex; - elementsCount -= count; - - Arrays.fill(buffer, elementsCount, elementsCount + count, null); - } - - /** {@inheritDoc} */ - @Override - public boolean removeElement(KType e1) { - return removeFirst(e1) != -1; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(KType e1) { - final int index = indexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(KType e1) { - final int index = lastIndexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(KType e1) { - int to = 0; - for (int from = 0; from < elementsCount; from++) { - if (this.equals(e1, buffer[from])) { - continue; - } - if (to != from) { - buffer[to] = buffer[from]; - } - to++; - } - final int deleted = elementsCount - to; - this.elementsCount = to; - - Arrays.fill(buffer, elementsCount, elementsCount + deleted, null); - - return deleted; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(KType e1) { - return indexOf(e1) >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexOf(KType e1) { - for (int i = 0; i < elementsCount; i++) { - if (this.equals(e1, buffer[i])) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int lastIndexOf(KType e1) { - for (int i = elementsCount - 1; i >= 0; i--) { - if (this.equals(e1, buffer[i])) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return elementsCount == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (expectedElements > bufferLen) { - ensureBufferSpace(expectedElements - size()); - } - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (elementsCount + expectedAdditions > bufferLen) { - final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); - assert newSize >= elementsCount + expectedAdditions - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - this.buffer = Arrays.copyOf(buffer, newSize); - } - } - - /** - * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be - * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated - * values will be reset to the default value (zero). If the list is expanded, the elements beyond - * the current size are initialized with JVM-defaults (zero or null values). - */ - public void resize(int newSize) { - if (newSize <= buffer.length) { - if (newSize < elementsCount) { - Arrays.fill(buffer, newSize, elementsCount, null); - } else { - Arrays.fill(buffer, elementsCount, newSize, null); - } - } else { - ensureCapacity(newSize); - } - this.elementsCount = newSize; - } - - /** {@inheritDoc} */ - @Override - public int size() { - return elementsCount; - } - - /** Trim the internal buffer to the current size. */ - public void trimToSize() { - if (size() != this.buffer.length) { - this.buffer = (KType[]) toArray(); - } - } - - /** - * Sets the number of stored elements to zero. Releases and initializes the internal storage array - * to default values. To clear the list without cleaning the buffer, simply set the {@link - * #elementsCount} field to zero. - */ - @Override - public void clear() { - Arrays.fill(buffer, 0, elementsCount, null); - this.elementsCount = 0; - } - - /** Sets the number of stored elements to zero and releases the internal storage array. */ - @Override - public void release() { - this.buffer = (KType[]) EMPTY_ARRAY; - this.elementsCount = 0; - } - - /** - * {@inheritDoc} - * - *

The returned array is sized to match exactly the number of elements of the stack. - */ - @Override - public Object[] toArray() { - - return Arrays.copyOf(buffer, elementsCount); - } - - /** {@inheritDoc} */ - @Override - @SuppressWarnings("unchecked") - public Stream stream() { - return (Stream) Arrays.stream(buffer, 0, size()); - } - - /** {@inheritDoc} */ - @Override - public ObjectIndexedContainer sort() { - Arrays.sort(buffer, 0, elementsCount); - return this; - } - - /** {@inheritDoc} */ - @Override - public ObjectIndexedContainer reverse() { - for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { - KType tmp = (KType) buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = tmp; - } - return this; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public ObjectArrayList clone() { - try { - - final ObjectArrayList cloned = (ObjectArrayList) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1, max = elementsCount; - for (int i = 0; i < max; i++) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. Equality comparison is performed with this object's {@link #equals(Object, - * Object)} method. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Compare index-aligned elements against another {@link ObjectIndexedContainer}. Equality - * comparison is performed with this object's {@link #equals(Object, Object)} method. - */ - protected boolean equalElements(ObjectArrayList other) { - int max = size(); - if (other.size() != max) { - return false; - } - - for (int i = 0; i < max; i++) { - if (!this.equals(get(i), other.get(i))) { - return false; - } - } - - return true; - } - - @Override - public long ramBytesAllocated() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); - } - - /** An iterator implementation for {@link ObjectArrayList#iterator}. */ - static final class ValueIterator extends AbstractIterator> { - private final ObjectCursor cursor; - - private final KType[] buffer; - private final int size; - - public ValueIterator(KType[] buffer, int size) { - this.cursor = new ObjectCursor(); - this.cursor.index = -1; - this.size = size; - this.buffer = buffer; - } - - @Override - protected ObjectCursor fetch() { - if (cursor.index + 1 == size) return done(); - - cursor.value = buffer[++cursor.index]; - return cursor; - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new ValueIterator((KType[]) buffer, size()); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - return forEach(procedure, 0, size()); - } - - /** - * Applies procedure to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive. - */ - public > T forEach( - T procedure, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final KType[] buffer = (KType[]) this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - procedure.apply(buffer[i]); - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - final KType[] buffer = (KType[]) this.buffer; - final int elementsCount = this.elementsCount; - int to = 0; - int from = 0; - try { - for (; from < elementsCount; from++) { - if (predicate.apply(buffer[from])) { - buffer[from] = null; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = null; - } - to++; - } - } finally { - // Keep the list in a consistent state, even if the predicate throws an exception. - for (; from < elementsCount; from++) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = null; - } - to++; - } - - this.elementsCount = to; - } - - return elementsCount - to; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - return forEach(predicate, 0, size()); - } - - /** - * Applies predicate to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive, or until predicate returns false. - */ - public > T forEach( - T predicate, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final KType[] buffer = (KType[]) this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - if (!predicate.apply(buffer[i])) break; - } - - return predicate; - } - - /** - * Create a list from a variable number of arguments or an array of Object. The - * elements are copied from the argument to the internal buffer. - */ - @SafeVarargs - public static ObjectArrayList from(KType... elements) { - final ObjectArrayList list = new ObjectArrayList(elements.length); - list.add(elements); - return list; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectBufferVisualizer.java b/sources/main/java/com/carrotsearch/hppc/ObjectBufferVisualizer.java deleted file mode 100644 index c7a988f7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectBufferVisualizer.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Reused buffer visualization routines. - * - * @see ObjectSet#visualizeKeyDistribution(int) - * @see ObjectVTypeMap#visualizeKeyDistribution(int) - */ -class ObjectBufferVisualizer { - static String visualizeKeyDistribution(Object[] buffer, int max, int characters) { - final StringBuilder b = new StringBuilder(); - final char[] chars = ".123456789X".toCharArray(); - for (int i = 1, start = -1; i <= characters; i++) { - int end = (int) ((long) i * max / characters); - - if (start + 1 <= end) { - int taken = 0; - int slots = 0; - for (int slot = start + 1; slot <= end; slot++, slots++) { - if (!((buffer[slot]) == null)) { - taken++; - } - } - b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); - start = end; - } - } - while (b.length() < characters) { - b.append(' '); - } - return b.toString(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectByteAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectByteAssociativeContainer.java deleted file mode 100644 index a5904161..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectByteAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ObjectContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ObjectByteAssociativeContainer extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(KType key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectBytePredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectByteProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectBytePredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ObjectCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ByteContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectByteHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectByteHashMap.java deleted file mode 100644 index 4de468b8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectByteHashMap.java +++ /dev/null @@ -1,1089 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of Object to byte, implemented using open addressing with - * linear probing for collision resolution. Supports null key. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ObjectByteHashMap - implements ObjectByteMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public Object[] keys; - - /** The array holding values. */ - public byte[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ObjectByteHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectByteHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectByteHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectByteHashMap(ObjectByteAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public byte put(KType key, byte value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == null)) { - byte previousValue = hasEmptyKey ? values[mask + 1] : ((byte) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final byte previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ObjectByteAssociativeContainer container) { - final int count = size(); - for (ObjectByteCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (ObjectByteCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public byte putOrAdd(KType key, byte putValue, byte incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((byte) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public byte addTo(KType key, byte incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public byte remove(KType key) { - final int mask = this.mask; - if (((key) == null)) { - if (!hasEmptyKey) { - return ((byte) 0); - } - hasEmptyKey = false; - byte previousValue = values[mask + 1]; - values[mask + 1] = ((byte) 0); - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final byte previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ObjectLookupContainer) { - if (hasEmptyKey && other.contains(null)) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ObjectCursor c : other) { - remove((KType) c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectBytePredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(null, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - } - - final KType[] keys = (KType[]) this.keys; - final byte[] values = this.values; - for (int slot = 0; slot <= mask; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(null)) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public byte get(KType key) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : ((byte) 0); - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public byte getOrDefault(KType key, byte defaultValue) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(KType key) { - if (((key) == null)) { - return hasEmptyKey; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(KType key) { - final int mask = this.mask; - if (((key) == null)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public byte indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public byte indexReplace(int index, byte newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - byte previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, KType key, byte value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == null)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == null); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public byte indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - byte previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((byte) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ObjectByteCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Equality comparison is - * performed with this object's {@link #equals(Object, Object)} method. - */ - protected boolean equalElements(ObjectByteHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ObjectByteCursor c : other) { - KType key = (KType) c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final KType[] prevKeys = (KType[]) this.keys; - final byte[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectByteCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ObjectByteCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectByteCursor fetch() { - final int mask = ObjectByteHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = null; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final KType[] keys = (KType[]) this.keys; - final byte[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(null, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final KType[] keys = (KType[]) this.keys; - final byte[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(null, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final ObjectByteHashMap owner = ObjectByteHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectByteProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectBytePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final KType e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ObjectByteHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = null; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ByteCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractByteCollection { - private final ObjectByteHashMap owner = ObjectByteHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(byte value) { - for (ObjectByteCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ObjectByteCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ObjectByteCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final byte e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final BytePredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ByteCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ByteCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ByteCursor fetch() { - final int mask = ObjectByteHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!(((KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ObjectByteHashMap clone() { - try { - - ObjectByteHashMap cloned = (ObjectByteHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ObjectByteCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectByteHashMap from(KType[] keys, byte[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectByteHashMap map = new ObjectByteHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(KType[] fromKeys, byte[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final KType[] keys = (KType[]) this.keys; - final byte[] values = this.values; - final int mask = this.mask; - KType existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == null)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == null)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - KType[] prevKeys = (KType[]) this.keys; - byte[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); - this.values = (new byte[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, KType pendingKey, byte pendingValue) { - assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final KType[] prevKeys = (KType[]) this.keys; - final byte[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final KType[] keys = (KType[]) this.keys; - final byte[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final KType existing = keys[slot]; - if (((existing) == null)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = null; - values[gapSlot] = ((byte) 0); - assigned--; - } - - protected boolean equals(Object v1, Object v2) { - return (v1 == v2) || (v1 != null && v1.equals(v2)); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectByteIdentityHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectByteIdentityHashMap.java deleted file mode 100644 index f9567cdd..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectByteIdentityHashMap.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -/** An identity hash map of Object to byte. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeIdentityHashMap.java") -public class ObjectByteIdentityHashMap extends ObjectByteHashMap { - /** New instance with sane defaults. */ - public ObjectByteIdentityHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectByteIdentityHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectByteIdentityHashMap(int expectedElements, double loadFactor) { - super(expectedElements, loadFactor); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectByteIdentityHashMap(ObjectByteAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - @Override - public int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(System.identityHashCode(key)); - } - - @Override - public boolean equals(Object v1, Object v2) { - return v1 == v2; - } - - @SuppressWarnings("unchecked") - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectByteIdentityHashMap from(KType[] keys, byte[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectByteIdentityHashMap map = new ObjectByteIdentityHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectByteMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectByteMap.java deleted file mode 100644 index 9b4ac38a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectByteMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectByteCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ObjectByteMap extends ObjectByteAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public byte get(KType key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public byte getOrDefault(KType key, byte defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public byte put(KType key, byte value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(KType key, byte value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ObjectByteAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public byte putOrAdd(KType key, byte putValue, byte incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public byte addTo(KType key, byte additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public byte remove(KType key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ObjectByteMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(KType key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexReplace(int index, byte newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, KType key, byte value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectCharAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectCharAssociativeContainer.java deleted file mode 100644 index fc06ba23..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectCharAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ObjectContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ObjectCharAssociativeContainer extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(KType key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectCharPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectCharProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectCharPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ObjectCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public CharContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectCharHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectCharHashMap.java deleted file mode 100644 index b71d892c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectCharHashMap.java +++ /dev/null @@ -1,1089 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of Object to char, implemented using open addressing with - * linear probing for collision resolution. Supports null key. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ObjectCharHashMap - implements ObjectCharMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public Object[] keys; - - /** The array holding values. */ - public char[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ObjectCharHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectCharHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectCharHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectCharHashMap(ObjectCharAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public char put(KType key, char value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == null)) { - char previousValue = hasEmptyKey ? values[mask + 1] : ((char) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final char previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ObjectCharAssociativeContainer container) { - final int count = size(); - for (ObjectCharCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (ObjectCharCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public char putOrAdd(KType key, char putValue, char incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((char) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public char addTo(KType key, char incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public char remove(KType key) { - final int mask = this.mask; - if (((key) == null)) { - if (!hasEmptyKey) { - return ((char) 0); - } - hasEmptyKey = false; - char previousValue = values[mask + 1]; - values[mask + 1] = ((char) 0); - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final char previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ObjectLookupContainer) { - if (hasEmptyKey && other.contains(null)) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ObjectCursor c : other) { - remove((KType) c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectCharPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(null, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - } - - final KType[] keys = (KType[]) this.keys; - final char[] values = this.values; - for (int slot = 0; slot <= mask; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(null)) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public char get(KType key) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : ((char) 0); - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public char getOrDefault(KType key, char defaultValue) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(KType key) { - if (((key) == null)) { - return hasEmptyKey; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(KType key) { - final int mask = this.mask; - if (((key) == null)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public char indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public char indexReplace(int index, char newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - char previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, KType key, char value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == null)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == null); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public char indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - char previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((char) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ObjectCharCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Equality comparison is - * performed with this object's {@link #equals(Object, Object)} method. - */ - protected boolean equalElements(ObjectCharHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ObjectCharCursor c : other) { - KType key = (KType) c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final KType[] prevKeys = (KType[]) this.keys; - final char[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectCharCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ObjectCharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCharCursor fetch() { - final int mask = ObjectCharHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = null; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final KType[] keys = (KType[]) this.keys; - final char[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(null, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final KType[] keys = (KType[]) this.keys; - final char[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(null, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final ObjectCharHashMap owner = ObjectCharHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectCharProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectCharPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final KType e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ObjectCharHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = null; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public CharCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractCharCollection { - private final ObjectCharHashMap owner = ObjectCharHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(char value) { - for (ObjectCharCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ObjectCharCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ObjectCharCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final char e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final CharPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = ObjectCharHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!(((KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ObjectCharHashMap clone() { - try { - - ObjectCharHashMap cloned = (ObjectCharHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ObjectCharCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectCharHashMap from(KType[] keys, char[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectCharHashMap map = new ObjectCharHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(KType[] fromKeys, char[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final KType[] keys = (KType[]) this.keys; - final char[] values = this.values; - final int mask = this.mask; - KType existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == null)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == null)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - KType[] prevKeys = (KType[]) this.keys; - char[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); - this.values = (new char[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, KType pendingKey, char pendingValue) { - assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final KType[] prevKeys = (KType[]) this.keys; - final char[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final KType[] keys = (KType[]) this.keys; - final char[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final KType existing = keys[slot]; - if (((existing) == null)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = null; - values[gapSlot] = ((char) 0); - assigned--; - } - - protected boolean equals(Object v1, Object v2) { - return (v1 == v2) || (v1 != null && v1.equals(v2)); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectCharIdentityHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectCharIdentityHashMap.java deleted file mode 100644 index d373e7f0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectCharIdentityHashMap.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -/** An identity hash map of Object to char. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeIdentityHashMap.java") -public class ObjectCharIdentityHashMap extends ObjectCharHashMap { - /** New instance with sane defaults. */ - public ObjectCharIdentityHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectCharIdentityHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectCharIdentityHashMap(int expectedElements, double loadFactor) { - super(expectedElements, loadFactor); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectCharIdentityHashMap(ObjectCharAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - @Override - public int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(System.identityHashCode(key)); - } - - @Override - public boolean equals(Object v1, Object v2) { - return v1 == v2; - } - - @SuppressWarnings("unchecked") - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectCharIdentityHashMap from(KType[] keys, char[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectCharIdentityHashMap map = new ObjectCharIdentityHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectCharMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectCharMap.java deleted file mode 100644 index ab636b51..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectCharMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectCharCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ObjectCharMap extends ObjectCharAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public char get(KType key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public char getOrDefault(KType key, char defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public char put(KType key, char value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(KType key, char value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ObjectCharAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public char putOrAdd(KType key, char putValue, char incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public char addTo(KType key, char additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public char remove(KType key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ObjectCharMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(KType key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexReplace(int index, char newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, KType key, char value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectCollection.java b/sources/main/java/com/carrotsearch/hppc/ObjectCollection.java deleted file mode 100644 index 447e46de..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectCollection.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.predicates.ObjectPredicate; - -/** - * A collection allows basic, efficient operations on sets of elements (difference and - * intersection). - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") -public interface ObjectCollection extends ObjectContainer { - /** - * Removes all occurrences of e from this collection. - * - * @param e Element to be removed from this collection, if present. - * @return The number of removed elements as a result of this call. - */ - public int removeAll(KType e); - - /** - * Removes all elements in this collection that are present in c. - * - * @return Returns the number of removed elements. - */ - public int removeAll(ObjectLookupContainer c); - - /** - * Removes all elements in this collection for which the given predicate returns true - * . - * - * @return Returns the number of removed elements. - */ - public int removeAll(ObjectPredicate predicate); - - /** - * Keeps all elements in this collection that are present in c. Runs in time - * proportional to the number of elements in this collection. Equivalent of sets intersection. - * - * @return Returns the number of removed elements. - */ - public int retainAll(ObjectLookupContainer c); - - /** - * Keeps all elements in this collection for which the given predicate returns true. - * - * @return Returns the number of removed elements. - */ - public int retainAll(ObjectPredicate predicate); - - /** - * Removes all elements from this collection. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectContainer.java deleted file mode 100644 index 6e8cd488..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectContainer.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectCursor; -import com.carrotsearch.hppc.predicates.ObjectPredicate; -import com.carrotsearch.hppc.procedures.ObjectProcedure; -import java.util.Iterator; - -/** A generic container holding Objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") -public interface ObjectContainer extends Iterable> { - /** - * Returns an iterator to a cursor traversing the collection. The order of traversal is not - * defined. More than one cursor may be active at a time. The behavior of iterators is undefined - * if structural changes are made to the underlying collection. - * - *

The iterator is implemented as a cursor and it returns the same cursor instance on - * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current - * list's value (or index in the list) use the cursor's public fields. An example is shown below. - * - *

-   * for (ObjectCursor<Object> c : container) {
-   *   System.out.println("index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator> iterator(); - - /** - * Lookup a given element in the container. This operation has no speed guarantees (may be linear - * with respect to the size of this container). - * - * @return Returns true if this container has an element equal to e. - */ - public boolean contains(KType e); - - /** - * Return the current number of elements in this container. The time for calculating the - * container's size may take O(n) time, although implementing classes should try to - * maintain the current size and return in constant time. - */ - public int size(); - - /** Shortcut for size() == 0. */ - public boolean isEmpty(); - - /** - * Copies all elements of this container to an array. - * - *

The returned array is always a copy, regardless of the storage used by the container. - */ - public Object[] toArray(); - - /** - * Copies all elements of this container to a dynamically created array of the given component - * type. - * - * @throws ArrayStoreException Thrown if this container's elements are not assignable to the - * array's component type. - */ - public T[] toArray(Class componentClass); - - /** - * Applies a procedure to all container elements. Returns the argument (any subclass - * of {@link ObjectProcedure}. This lets the caller to call methods of the argument by chaining - * the call (even if the argument is an anonymous type) to retrieve computed values, for example - * (IntContainer): - * - *

-   * int count = container.forEach(new IntProcedure() {
-   *   int count; // this is a field declaration in an anonymous class.
-   *
-   *   public void apply(int value) {
-   *     count++;
-   *   }
-   * }).count;
-   * 
- */ - public > T forEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public > T forEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectDeque.java b/sources/main/java/com/carrotsearch/hppc/ObjectDeque.java deleted file mode 100644 index 2e6f62f3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectDeque.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectCursor; -import com.carrotsearch.hppc.predicates.ObjectPredicate; -import com.carrotsearch.hppc.procedures.ObjectProcedure; -import java.util.Deque; -import java.util.Iterator; - -/** - * A linear collection that supports element insertion and removal at both ends. - * - * @see Deque - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") -public interface ObjectDeque extends ObjectCollection { - /** - * Removes the first element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeFirst(KType e); - - /** - * Removes the last element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeLast(KType e); - - /** Inserts the specified element at the front of this deque. */ - public void addFirst(KType e); - - /** Inserts the specified element at the end of this deque. */ - public void addLast(KType e); - - /** - * Retrieves and removes the first element of this deque. - * - * @return the head (first) element of this deque. - */ - public KType removeFirst(); - - /** - * Retrieves and removes the last element of this deque. - * - * @return the tail of this deque. - */ - public KType removeLast(); - - /** - * Retrieves the first element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public KType getFirst(); - - /** - * Retrieves the last element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public KType getLast(); - - /** - * @return An iterator over elements in this deque in tail-to-head order. - */ - public Iterator> descendingIterator(); - - /** Applies a procedure to all elements in tail-to-head order. */ - public > T descendingForEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public > T descendingForEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectDoubleAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectDoubleAssociativeContainer.java deleted file mode 100644 index 0eb15e2a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectDoubleAssociativeContainer.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ObjectContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ObjectDoubleAssociativeContainer - extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *
-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(KType key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectDoublePredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectDoubleProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectDoublePredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ObjectCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public DoubleContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectDoubleHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectDoubleHashMap.java deleted file mode 100644 index bf3240c7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectDoubleHashMap.java +++ /dev/null @@ -1,1091 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of Object to double, implemented using open addressing with - * linear probing for collision resolution. Supports null key. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ObjectDoubleHashMap - implements ObjectDoubleMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public Object[] keys; - - /** The array holding values. */ - public double[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ObjectDoubleHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectDoubleHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectDoubleHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectDoubleHashMap(ObjectDoubleAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public double put(KType key, double value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == null)) { - double previousValue = hasEmptyKey ? values[mask + 1] : 0d; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final double previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ObjectDoubleAssociativeContainer container) { - final int count = size(); - for (ObjectDoubleCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (ObjectDoubleCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public double putOrAdd(KType key, double putValue, double incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((double) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public double addTo(KType key, double incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public double remove(KType key) { - final int mask = this.mask; - if (((key) == null)) { - if (!hasEmptyKey) { - return 0d; - } - hasEmptyKey = false; - double previousValue = values[mask + 1]; - values[mask + 1] = 0d; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final double previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ObjectLookupContainer) { - if (hasEmptyKey && other.contains(null)) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ObjectCursor c : other) { - remove((KType) c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectDoublePredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(null, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - } - - final KType[] keys = (KType[]) this.keys; - final double[] values = this.values; - for (int slot = 0; slot <= mask; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(null)) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public double get(KType key) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : 0d; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public double getOrDefault(KType key, double defaultValue) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(KType key) { - if (((key) == null)) { - return hasEmptyKey; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(KType key) { - final int mask = this.mask; - if (((key) == null)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public double indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public double indexReplace(int index, double newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - double previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, KType key, double value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == null)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == null); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public double indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - double previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0d; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ObjectDoubleCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Equality comparison is - * performed with this object's {@link #equals(Object, Object)} method. - */ - protected boolean equalElements(ObjectDoubleHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ObjectDoubleCursor c : other) { - KType key = (KType) c.key; - if (!containsKey(key) - || !(Double.doubleToLongBits(c.value) == Double.doubleToLongBits(get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final KType[] prevKeys = (KType[]) this.keys; - final double[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectDoubleCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ObjectDoubleCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectDoubleCursor fetch() { - final int mask = ObjectDoubleHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = null; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final KType[] keys = (KType[]) this.keys; - final double[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(null, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final KType[] keys = (KType[]) this.keys; - final double[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(null, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final ObjectDoubleHashMap owner = ObjectDoubleHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectDoubleProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectDoublePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final KType e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ObjectDoubleHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = null; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public DoubleCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractDoubleCollection { - private final ObjectDoubleHashMap owner = ObjectDoubleHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(double value) { - for (ObjectDoubleCursor c : owner) { - if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ObjectDoubleCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ObjectDoubleCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final double e) { - return owner.removeAll( - (key, value) -> (Double.doubleToLongBits(e) == Double.doubleToLongBits(value))); - } - - @Override - public int removeAll(final DoublePredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final DoubleCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new DoubleCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected DoubleCursor fetch() { - final int mask = ObjectDoubleHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!(((KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ObjectDoubleHashMap clone() { - try { - - ObjectDoubleHashMap cloned = (ObjectDoubleHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ObjectDoubleCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectDoubleHashMap from(KType[] keys, double[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectDoubleHashMap map = new ObjectDoubleHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(KType[] fromKeys, double[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final KType[] keys = (KType[]) this.keys; - final double[] values = this.values; - final int mask = this.mask; - KType existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == null)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == null)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - KType[] prevKeys = (KType[]) this.keys; - double[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); - this.values = (new double[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, KType pendingKey, double pendingValue) { - assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final KType[] prevKeys = (KType[]) this.keys; - final double[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final KType[] keys = (KType[]) this.keys; - final double[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final KType existing = keys[slot]; - if (((existing) == null)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = null; - values[gapSlot] = 0d; - assigned--; - } - - protected boolean equals(Object v1, Object v2) { - return (v1 == v2) || (v1 != null && v1.equals(v2)); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectDoubleIdentityHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectDoubleIdentityHashMap.java deleted file mode 100644 index b034adf4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectDoubleIdentityHashMap.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -/** An identity hash map of Object to double. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeIdentityHashMap.java") -public class ObjectDoubleIdentityHashMap extends ObjectDoubleHashMap { - /** New instance with sane defaults. */ - public ObjectDoubleIdentityHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectDoubleIdentityHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectDoubleIdentityHashMap(int expectedElements, double loadFactor) { - super(expectedElements, loadFactor); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectDoubleIdentityHashMap(ObjectDoubleAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - @Override - public int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(System.identityHashCode(key)); - } - - @Override - public boolean equals(Object v1, Object v2) { - return v1 == v2; - } - - @SuppressWarnings("unchecked") - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectDoubleIdentityHashMap from(KType[] keys, double[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectDoubleIdentityHashMap map = new ObjectDoubleIdentityHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectDoubleMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectDoubleMap.java deleted file mode 100644 index 595fc978..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectDoubleMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectDoubleCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ObjectDoubleMap extends ObjectDoubleAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public double get(KType key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public double getOrDefault(KType key, double defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public double put(KType key, double value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(KType key, double value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ObjectDoubleAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public double putOrAdd(KType key, double putValue, double incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public double addTo(KType key, double additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public double remove(KType key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ObjectDoubleMap} and both objects contains exactly the - * same key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(KType key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexReplace(int index, double newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, KType key, double value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectFloatAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectFloatAssociativeContainer.java deleted file mode 100644 index a7448b25..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectFloatAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ObjectContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ObjectFloatAssociativeContainer extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(KType key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectFloatPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectFloatProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectFloatPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ObjectCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public FloatContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectFloatHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectFloatHashMap.java deleted file mode 100644 index 2dc4c98e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectFloatHashMap.java +++ /dev/null @@ -1,1090 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of Object to float, implemented using open addressing with - * linear probing for collision resolution. Supports null key. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ObjectFloatHashMap - implements ObjectFloatMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public Object[] keys; - - /** The array holding values. */ - public float[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ObjectFloatHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectFloatHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectFloatHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectFloatHashMap(ObjectFloatAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public float put(KType key, float value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == null)) { - float previousValue = hasEmptyKey ? values[mask + 1] : 0f; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final float previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ObjectFloatAssociativeContainer container) { - final int count = size(); - for (ObjectFloatCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (ObjectFloatCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public float putOrAdd(KType key, float putValue, float incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((float) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public float addTo(KType key, float incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public float remove(KType key) { - final int mask = this.mask; - if (((key) == null)) { - if (!hasEmptyKey) { - return 0f; - } - hasEmptyKey = false; - float previousValue = values[mask + 1]; - values[mask + 1] = 0f; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final float previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ObjectLookupContainer) { - if (hasEmptyKey && other.contains(null)) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ObjectCursor c : other) { - remove((KType) c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectFloatPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(null, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - } - - final KType[] keys = (KType[]) this.keys; - final float[] values = this.values; - for (int slot = 0; slot <= mask; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(null)) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public float get(KType key) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : 0f; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public float getOrDefault(KType key, float defaultValue) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(KType key) { - if (((key) == null)) { - return hasEmptyKey; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(KType key) { - final int mask = this.mask; - if (((key) == null)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public float indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public float indexReplace(int index, float newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - float previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, KType key, float value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == null)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == null); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public float indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - float previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0f; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ObjectFloatCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Equality comparison is - * performed with this object's {@link #equals(Object, Object)} method. - */ - protected boolean equalElements(ObjectFloatHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ObjectFloatCursor c : other) { - KType key = (KType) c.key; - if (!containsKey(key) || !(Float.floatToIntBits(c.value) == Float.floatToIntBits(get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final KType[] prevKeys = (KType[]) this.keys; - final float[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectFloatCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ObjectFloatCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectFloatCursor fetch() { - final int mask = ObjectFloatHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = null; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final KType[] keys = (KType[]) this.keys; - final float[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(null, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final KType[] keys = (KType[]) this.keys; - final float[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(null, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final ObjectFloatHashMap owner = ObjectFloatHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectFloatProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectFloatPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final KType e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ObjectFloatHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = null; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public FloatCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractFloatCollection { - private final ObjectFloatHashMap owner = ObjectFloatHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(float value) { - for (ObjectFloatCursor c : owner) { - if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ObjectFloatCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ObjectFloatCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final float e) { - return owner.removeAll( - (key, value) -> (Float.floatToIntBits(e) == Float.floatToIntBits(value))); - } - - @Override - public int removeAll(final FloatPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final FloatCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new FloatCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected FloatCursor fetch() { - final int mask = ObjectFloatHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!(((KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ObjectFloatHashMap clone() { - try { - - ObjectFloatHashMap cloned = (ObjectFloatHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ObjectFloatCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectFloatHashMap from(KType[] keys, float[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectFloatHashMap map = new ObjectFloatHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(KType[] fromKeys, float[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final KType[] keys = (KType[]) this.keys; - final float[] values = this.values; - final int mask = this.mask; - KType existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == null)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == null)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - KType[] prevKeys = (KType[]) this.keys; - float[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); - this.values = (new float[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, KType pendingKey, float pendingValue) { - assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final KType[] prevKeys = (KType[]) this.keys; - final float[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final KType[] keys = (KType[]) this.keys; - final float[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final KType existing = keys[slot]; - if (((existing) == null)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = null; - values[gapSlot] = 0f; - assigned--; - } - - protected boolean equals(Object v1, Object v2) { - return (v1 == v2) || (v1 != null && v1.equals(v2)); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectFloatIdentityHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectFloatIdentityHashMap.java deleted file mode 100644 index cfb63d0c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectFloatIdentityHashMap.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -/** An identity hash map of Object to float. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeIdentityHashMap.java") -public class ObjectFloatIdentityHashMap extends ObjectFloatHashMap { - /** New instance with sane defaults. */ - public ObjectFloatIdentityHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectFloatIdentityHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectFloatIdentityHashMap(int expectedElements, double loadFactor) { - super(expectedElements, loadFactor); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectFloatIdentityHashMap(ObjectFloatAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - @Override - public int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(System.identityHashCode(key)); - } - - @Override - public boolean equals(Object v1, Object v2) { - return v1 == v2; - } - - @SuppressWarnings("unchecked") - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectFloatIdentityHashMap from(KType[] keys, float[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectFloatIdentityHashMap map = new ObjectFloatIdentityHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectFloatMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectFloatMap.java deleted file mode 100644 index 8feee948..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectFloatMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectFloatCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ObjectFloatMap extends ObjectFloatAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public float get(KType key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public float getOrDefault(KType key, float defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public float put(KType key, float value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(KType key, float value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ObjectFloatAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public float putOrAdd(KType key, float putValue, float incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public float addTo(KType key, float additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public float remove(KType key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ObjectFloatMap} and both objects contains exactly the - * same key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(KType key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexReplace(int index, float newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, KType key, float value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectHashSet.java b/sources/main/java/com/carrotsearch/hppc/ObjectHashSet.java deleted file mode 100644 index 1a37b23e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectHashSet.java +++ /dev/null @@ -1,797 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash set of Objects, implemented using open addressing with linear probing for - * collision resolution. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java") -public class ObjectHashSet extends AbstractObjectCollection - implements ObjectLookupContainer, - ObjectSet, - Preallocable, - Cloneable, - Accountable { - /** The hash array holding keys. */ - public Object[] keys; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any. - * - * @see #size() - * @see #hasEmptyKey - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** - * New instance with sane defaults. - * - * @see #ObjectHashSet(int, double) - */ - public ObjectHashSet() { - this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with sane defaults. - * - * @see #ObjectHashSet(int, double) - */ - public ObjectHashSet(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectHashSet(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** New instance copying elements from another {@link ObjectContainer}. */ - public ObjectHashSet(ObjectContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public boolean add(KType key) { - if (((key) == null)) { - assert ((keys[mask + 1]) == null); - boolean added = !hasEmptyKey; - hasEmptyKey = true; - return added; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return false; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key); - } else { - keys[slot] = key; - } - - assigned++; - return true; - } - } - - /** - * Adds all elements from the given list (vararg) to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - @SafeVarargs - public final int addAll(KType... elements) { - ensureCapacity(elements.length); - int count = 0; - for (KType e : elements) { - if (add(e)) { - count++; - } - } - return count; - } - - /** - * Adds all elements from the given {@link ObjectContainer} to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public int addAll(ObjectContainer container) { - ensureCapacity(container.size()); - return addAll((Iterable>) container); - } - - /** - * Adds all elements from the given iterable to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public int addAll(Iterable> iterable) { - int count = 0; - for (ObjectCursor cursor : iterable) { - if (add(cursor.value)) { - count++; - } - } - return count; - } - - /** {@inheritDoc} */ - @Override - public Object[] toArray() { - - final KType[] cloned = ((KType[]) new Object[size()]); - int j = 0; - if (hasEmptyKey) { - cloned[j++] = null; - } - - final KType[] keys = (KType[]) this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - KType existing; - if (!((existing = keys[slot]) == null)) { - cloned[j++] = existing; - } - } - - return cloned; - } - - /** An alias for the (preferred) {@link #removeAll}. */ - public boolean remove(KType key) { - if (((key) == null)) { - boolean hadEmptyKey = hasEmptyKey; - hasEmptyKey = false; - return hadEmptyKey; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - shiftConflictingKeys(slot); - return true; - } - slot = (slot + 1) & mask; - } - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(KType key) { - return remove(key) ? 1 : 0; - } - - /** - * Removes all keys present in a given container. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectContainer other) { - final int before = size(); - - // Try to iterate over the smaller set or over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ObjectLookupContainer) { - if (hasEmptyKey && other.contains(null)) { - hasEmptyKey = false; - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ObjectCursor c : other) { - remove((KType) c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(null)) { - hasEmptyKey = false; - } - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null)) { - if (predicate.apply(existing)) { - shiftConflictingKeys(slot); - continue; // Repeat the check for the same slot i (shifted). - } - } - slot++; - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public boolean contains(KType key) { - if (((key) == null)) { - return hasEmptyKey; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return true; - } - slot = (slot + 1) & mask; - } - return false; - } - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - Arrays.fill(keys, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - keys = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final KType[] prevKeys = (KType[]) this.keys; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys); - } - } - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - final KType[] keys = (KType[]) this.keys; - for (int slot = mask; slot >= 0; slot--) { - KType existing; - if (!((existing = keys[slot]) == null)) { - h += BitMixer.mix(existing); - } - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Equality comparison is - * performed with this object's {@link #equals(Object, Object)} method. - */ - private boolean sameKeys(ObjectSet other) { - if (other.size() != size()) { - return false; - } - - for (ObjectCursor c : other) { - if (!contains((KType) c.value)) { - return false; - } - } - - return true; - } - - /** {@inheritDoc} */ - @Override - public ObjectHashSet clone() { - try { - - ObjectHashSet cloned = (ObjectHashSet) super.clone(); - cloned.keys = keys.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - @Override - public long ramBytesAllocated() { - // int: assigned, mask, keyMixer, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys); - } - - @Override - public long ramBytesUsed() { - // int: assigned, mask, keyMixer, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - protected final class EntryIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ObjectHashSet.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = null; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - if (hasEmptyKey) { - procedure.apply(null); - } - - final KType[] keys = (KType[]) this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - KType existing; - if (!((existing = keys[slot]) == null)) { - procedure.apply(existing); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - if (hasEmptyKey) { - if (!predicate.apply(null)) { - return predicate; - } - } - - final KType[] keys = (KType[]) this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - KType existing; - if (!((existing = keys[slot]) == null)) { - if (!predicate.apply(existing)) { - break; - } - } - } - - return predicate; - } - - /** - * Create a set from a variable number of arguments or an array of Object. The - * elements are copied from the argument to the internal buffer. - */ - @SafeVarargs - public static ObjectHashSet from(KType... elements) { - final ObjectHashSet set = new ObjectHashSet(elements.length); - set.addAll(elements); - return set; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up logic in - * certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between modifications (it will not be affected by read-only - * operations). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the set. - * @return A non-negative value of the logical "index" of the key in the set or a negative value - * if the key did not exist. - */ - public int indexOf(KType key) { - final int mask = this.mask; - if (((key) == null)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index) { - assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** - * Returns the exact value of the existing key. This method makes sense for sets of objects which - * define custom key-equality relationship. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the equivalent key currently stored in the set. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public KType indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return (KType) keys[index]; - } - - /** - * Replaces the existing equivalent key with the given one and returns any previous value stored - * for that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key - * currently stored at the provided index. - * @return Returns the previous key stored in the set. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public KType indexReplace(int index, KType equivalentKey) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - assert this.equals(keys[index], equivalentKey); - - KType previousValue = (KType) keys[index]; - keys[index] = equivalentKey; - return previousValue; - } - - /** - * Inserts a key for an index that is not present in the set. This method may help in avoiding - * double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public void indexInsert(int index, KType key) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == null)) { - assert index == mask + 1; - assert ((keys[index]) == null); - hasEmptyKey = true; - } else { - assert ((keys[index]) == null); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key); - } else { - keys[index] = key; - } - - assigned++; - } - } - - /** - * Removes a key at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public void indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - if (index > mask) { - hasEmptyKey = false; - } else { - shiftConflictingKeys(index); - } - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(KType[] fromKeys) { - assert HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored keys into the new buffers. - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - KType existing; - for (int i = fromKeys.length - 1; --i >= 0; ) { - if (!((existing = fromKeys[i]) == null)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == null)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - KType[] prevKeys = (KType[]) this.keys; - try { - int emptyElementSlot = 1; - this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.keys == null ? 0 : size(), arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key to be inserted into the buffer but there is not - * enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, KType pendingKey) { - assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final KType[] prevKeys = (KType[]) this.keys; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - - // Rehash old keys, including the pending key. - rehash(prevKeys); - } - - /** Shift all the slot-conflicting keys allocated to (and including) slot. */ - protected void shiftConflictingKeys(int gapSlot) { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final KType existing = keys[slot]; - if (((existing) == null)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = null; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectIdentityHashSet.java b/sources/main/java/com/carrotsearch/hppc/ObjectIdentityHashSet.java deleted file mode 100644 index 4efb528d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectIdentityHashSet.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -/** A reference-equality (identity) hash set. */ -public class ObjectIdentityHashSet extends ObjectHashSet { - /** New instance with sane defaults. */ - public ObjectIdentityHashSet() { - this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); - } - - /** New instance with sane defaults. */ - public ObjectIdentityHashSet(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectIdentityHashSet(int expectedElements, double loadFactor) { - super(expectedElements, loadFactor); - } - - /** New instance copying elements from another {@link ObjectContainer}. */ - public ObjectIdentityHashSet(ObjectContainer container) { - this(container.size()); - addAll(container); - } - - @Override - protected int hashKey(KType key) { - assert key != null; // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(System.identityHashCode(key)); - } - - @Override - protected boolean equals(Object v1, Object v2) { - return v1 == v2; - } - - /** - * Create a set from a variable number of arguments or an array of KType. The - * elements are copied from the argument to the internal buffer. - */ - @SafeVarargs - public static ObjectIdentityHashSet from(KType... elements) { - final ObjectIdentityHashSet set = new ObjectIdentityHashSet(elements.length); - set.addAll(elements); - return set; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectIndexedContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectIndexedContainer.java deleted file mode 100644 index 37ce1fc4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectIndexedContainer.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.carrotsearch.hppc; - -import java.util.RandomAccess; -import java.util.stream.Stream; - -/** - * An indexed container provides random access to elements based on an index. Indexes - * are zero-based. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeIndexedContainer.java") -public interface ObjectIndexedContainer extends ObjectCollection, RandomAccess { - /** - * Removes the first element that equals e1, returning whether an element has been - * removed. - */ - public boolean removeElement(KType e1); - - /** - * Removes the first element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeFirst(KType e1); - - /** - * Removes the last element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeLast(KType e1); - - /** - * Returns the index of the first occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int indexOf(KType e1); - - /** - * Returns the index of the last occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int lastIndexOf(KType e1); - - /** Adds an element to the end of this container (the last index is incremented by one). */ - public void add(KType e1); - - /** - * Inserts the specified element at the specified position in this list. - * - * @param index The index at which the element should be inserted, shifting any existing and - * subsequent elements to the right. - */ - public void insert(int index, KType e1); - - /** - * Replaces the element at the specified position in this list with the specified element. - * - * @return Returns the previous value in the list. - */ - public KType set(int index, KType e1); - - /** - * @return Returns the element at index index from the list. - */ - public KType get(int index); - - /** - * Removes the element at the specified position in this container and returns it. - * - * @see #removeFirst - * @see #removeLast - * @see #removeAll - */ - public KType removeAt(int index); - - /** Removes and returns the last element of this container. This container must not be empty. */ - public KType removeLast(); - - /** - * Removes from this container all of the elements with indexes between fromIndex, - * inclusive, and toIndex, exclusive. - */ - public void removeRange(int fromIndex, int toIndex); - - /** Returns this container elements as a stream. */ - public Stream stream(); - - /** Sorts the elements in this container and returns this container. */ - public ObjectIndexedContainer sort(); - - /** Reverses the elements in this container and returns this container. */ - public ObjectIndexedContainer reverse(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectIntAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectIntAssociativeContainer.java deleted file mode 100644 index 13f68440..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectIntAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ObjectContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ObjectIntAssociativeContainer extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(KType key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectIntPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectIntProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectIntPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ObjectCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public IntContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectIntHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectIntHashMap.java deleted file mode 100644 index 47e49998..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectIntHashMap.java +++ /dev/null @@ -1,1089 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of Object to int, implemented using open addressing with - * linear probing for collision resolution. Supports null key. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ObjectIntHashMap - implements ObjectIntMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public Object[] keys; - - /** The array holding values. */ - public int[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ObjectIntHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectIntHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectIntHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectIntHashMap(ObjectIntAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public int put(KType key, int value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == null)) { - int previousValue = hasEmptyKey ? values[mask + 1] : 0; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final int previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ObjectIntAssociativeContainer container) { - final int count = size(); - for (ObjectIntCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (ObjectIntCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public int putOrAdd(KType key, int putValue, int incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((int) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public int addTo(KType key, int incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public int remove(KType key) { - final int mask = this.mask; - if (((key) == null)) { - if (!hasEmptyKey) { - return 0; - } - hasEmptyKey = false; - int previousValue = values[mask + 1]; - values[mask + 1] = 0; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final int previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ObjectLookupContainer) { - if (hasEmptyKey && other.contains(null)) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ObjectCursor c : other) { - remove((KType) c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectIntPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(null, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - } - - final KType[] keys = (KType[]) this.keys; - final int[] values = this.values; - for (int slot = 0; slot <= mask; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(null)) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int get(KType key) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : 0; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int getOrDefault(KType key, int defaultValue) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(KType key) { - if (((key) == null)) { - return hasEmptyKey; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(KType key) { - final int mask = this.mask; - if (((key) == null)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public int indexReplace(int index, int newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - int previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, KType key, int value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == null)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == null); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public int indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - int previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ObjectIntCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Equality comparison is - * performed with this object's {@link #equals(Object, Object)} method. - */ - protected boolean equalElements(ObjectIntHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ObjectIntCursor c : other) { - KType key = (KType) c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final KType[] prevKeys = (KType[]) this.keys; - final int[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectIntCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ObjectIntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectIntCursor fetch() { - final int mask = ObjectIntHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = null; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final KType[] keys = (KType[]) this.keys; - final int[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(null, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final KType[] keys = (KType[]) this.keys; - final int[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(null, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final ObjectIntHashMap owner = ObjectIntHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectIntProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectIntPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final KType e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ObjectIntHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = null; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public IntCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractIntCollection { - private final ObjectIntHashMap owner = ObjectIntHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(int value) { - for (ObjectIntCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ObjectIntCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ObjectIntCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final int e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final IntPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = ObjectIntHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!(((KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ObjectIntHashMap clone() { - try { - - ObjectIntHashMap cloned = (ObjectIntHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ObjectIntCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectIntHashMap from(KType[] keys, int[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectIntHashMap map = new ObjectIntHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(KType[] fromKeys, int[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final KType[] keys = (KType[]) this.keys; - final int[] values = this.values; - final int mask = this.mask; - KType existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == null)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == null)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - KType[] prevKeys = (KType[]) this.keys; - int[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); - this.values = (new int[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, KType pendingKey, int pendingValue) { - assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final KType[] prevKeys = (KType[]) this.keys; - final int[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final KType[] keys = (KType[]) this.keys; - final int[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final KType existing = keys[slot]; - if (((existing) == null)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = null; - values[gapSlot] = 0; - assigned--; - } - - protected boolean equals(Object v1, Object v2) { - return (v1 == v2) || (v1 != null && v1.equals(v2)); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectIntIdentityHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectIntIdentityHashMap.java deleted file mode 100644 index b471a1a7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectIntIdentityHashMap.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -/** An identity hash map of Object to int. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeIdentityHashMap.java") -public class ObjectIntIdentityHashMap extends ObjectIntHashMap { - /** New instance with sane defaults. */ - public ObjectIntIdentityHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectIntIdentityHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectIntIdentityHashMap(int expectedElements, double loadFactor) { - super(expectedElements, loadFactor); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectIntIdentityHashMap(ObjectIntAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - @Override - public int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(System.identityHashCode(key)); - } - - @Override - public boolean equals(Object v1, Object v2) { - return v1 == v2; - } - - @SuppressWarnings("unchecked") - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectIntIdentityHashMap from(KType[] keys, int[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectIntIdentityHashMap map = new ObjectIntIdentityHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectIntMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectIntMap.java deleted file mode 100644 index 5f87f0f6..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectIntMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectIntCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ObjectIntMap extends ObjectIntAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public int get(KType key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public int getOrDefault(KType key, int defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public int put(KType key, int value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(KType key, int value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ObjectIntAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public int putOrAdd(KType key, int putValue, int incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public int addTo(KType key, int additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public int remove(KType key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ObjectIntMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(KType key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexReplace(int index, int newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, KType key, int value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectLongAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectLongAssociativeContainer.java deleted file mode 100644 index 3d78e376..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectLongAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ObjectContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ObjectLongAssociativeContainer extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(KType key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectLongPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectLongProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectLongPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ObjectCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public LongContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectLongHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectLongHashMap.java deleted file mode 100644 index 1688a68d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectLongHashMap.java +++ /dev/null @@ -1,1089 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of Object to long, implemented using open addressing with - * linear probing for collision resolution. Supports null key. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ObjectLongHashMap - implements ObjectLongMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public Object[] keys; - - /** The array holding values. */ - public long[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ObjectLongHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectLongHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectLongHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectLongHashMap(ObjectLongAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public long put(KType key, long value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == null)) { - long previousValue = hasEmptyKey ? values[mask + 1] : 0L; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final long previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ObjectLongAssociativeContainer container) { - final int count = size(); - for (ObjectLongCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (ObjectLongCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public long putOrAdd(KType key, long putValue, long incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((long) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public long addTo(KType key, long incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public long remove(KType key) { - final int mask = this.mask; - if (((key) == null)) { - if (!hasEmptyKey) { - return 0L; - } - hasEmptyKey = false; - long previousValue = values[mask + 1]; - values[mask + 1] = 0L; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final long previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ObjectLookupContainer) { - if (hasEmptyKey && other.contains(null)) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ObjectCursor c : other) { - remove((KType) c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectLongPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(null, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - } - - final KType[] keys = (KType[]) this.keys; - final long[] values = this.values; - for (int slot = 0; slot <= mask; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(null)) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public long get(KType key) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : 0L; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public long getOrDefault(KType key, long defaultValue) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(KType key) { - if (((key) == null)) { - return hasEmptyKey; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(KType key) { - final int mask = this.mask; - if (((key) == null)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public long indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public long indexReplace(int index, long newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - long previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, KType key, long value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == null)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == null); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public long indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - long previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0L; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ObjectLongCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Equality comparison is - * performed with this object's {@link #equals(Object, Object)} method. - */ - protected boolean equalElements(ObjectLongHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ObjectLongCursor c : other) { - KType key = (KType) c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final KType[] prevKeys = (KType[]) this.keys; - final long[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectLongCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ObjectLongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectLongCursor fetch() { - final int mask = ObjectLongHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = null; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final KType[] keys = (KType[]) this.keys; - final long[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(null, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final KType[] keys = (KType[]) this.keys; - final long[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(null, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final ObjectLongHashMap owner = ObjectLongHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectLongProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectLongPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final KType e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ObjectLongHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = null; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public LongCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractLongCollection { - private final ObjectLongHashMap owner = ObjectLongHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(long value) { - for (ObjectLongCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ObjectLongCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ObjectLongCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final long e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final LongPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = ObjectLongHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!(((KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ObjectLongHashMap clone() { - try { - - ObjectLongHashMap cloned = (ObjectLongHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ObjectLongCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectLongHashMap from(KType[] keys, long[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectLongHashMap map = new ObjectLongHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(KType[] fromKeys, long[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final KType[] keys = (KType[]) this.keys; - final long[] values = this.values; - final int mask = this.mask; - KType existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == null)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == null)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - KType[] prevKeys = (KType[]) this.keys; - long[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); - this.values = (new long[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, KType pendingKey, long pendingValue) { - assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final KType[] prevKeys = (KType[]) this.keys; - final long[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final KType[] keys = (KType[]) this.keys; - final long[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final KType existing = keys[slot]; - if (((existing) == null)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = null; - values[gapSlot] = 0L; - assigned--; - } - - protected boolean equals(Object v1, Object v2) { - return (v1 == v2) || (v1 != null && v1.equals(v2)); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectLongIdentityHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectLongIdentityHashMap.java deleted file mode 100644 index 886d6742..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectLongIdentityHashMap.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -/** An identity hash map of Object to long. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeIdentityHashMap.java") -public class ObjectLongIdentityHashMap extends ObjectLongHashMap { - /** New instance with sane defaults. */ - public ObjectLongIdentityHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectLongIdentityHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectLongIdentityHashMap(int expectedElements, double loadFactor) { - super(expectedElements, loadFactor); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectLongIdentityHashMap(ObjectLongAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - @Override - public int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(System.identityHashCode(key)); - } - - @Override - public boolean equals(Object v1, Object v2) { - return v1 == v2; - } - - @SuppressWarnings("unchecked") - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectLongIdentityHashMap from(KType[] keys, long[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectLongIdentityHashMap map = new ObjectLongIdentityHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectLongMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectLongMap.java deleted file mode 100644 index 4cab9639..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectLongMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectLongCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ObjectLongMap extends ObjectLongAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public long get(KType key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public long getOrDefault(KType key, long defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public long put(KType key, long value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(KType key, long value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ObjectLongAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public long putOrAdd(KType key, long putValue, long incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public long addTo(KType key, long additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public long remove(KType key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ObjectLongMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(KType key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexReplace(int index, long newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, KType key, long value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectLookupContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectLookupContainer.java deleted file mode 100644 index ee0982c0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectLookupContainer.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Marker interface for containers that can check if they contain a given object in at least time - * O(log n) and ideally in amortized constant time O(1). - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeLookupContainer.java") -public interface ObjectLookupContainer extends ObjectContainer { - public boolean contains(KType e); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectObjectAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectObjectAssociativeContainer.java deleted file mode 100644 index 551388ef..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectObjectAssociativeContainer.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ObjectContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ObjectObjectAssociativeContainer - extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(KType key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectObjectPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectObjectProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectObjectPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ObjectCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ObjectContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectObjectHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectObjectHashMap.java deleted file mode 100644 index 855027cd..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectObjectHashMap.java +++ /dev/null @@ -1,1059 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of Object to Object, implemented using open addressing with - * linear probing for collision resolution. Supports null key. Supports null values. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ObjectObjectHashMap - implements ObjectObjectMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public Object[] keys; - - /** The array holding values. */ - public Object[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ObjectObjectHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectObjectHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectObjectHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectObjectHashMap( - ObjectObjectAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public VType put(KType key, VType value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == null)) { - VType previousValue = hasEmptyKey ? (VType) values[mask + 1] : null; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final VType previousValue = (VType) values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return null; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ObjectObjectAssociativeContainer container) { - final int count = size(); - for (ObjectObjectCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll( - Iterable> iterable) { - final int count = size(); - for (ObjectObjectCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** {@inheritDoc} */ - @Override - public VType remove(KType key) { - final int mask = this.mask; - if (((key) == null)) { - if (!hasEmptyKey) { - return null; - } - hasEmptyKey = false; - VType previousValue = (VType) values[mask + 1]; - values[mask + 1] = null; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final VType previousValue = (VType) values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return null; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ObjectLookupContainer) { - if (hasEmptyKey && other.contains(null)) { - hasEmptyKey = false; - values[mask + 1] = null; - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ObjectCursor c : other) { - remove((KType) c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectObjectPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(null, (VType) values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = null; - } - } - - final KType[] keys = (KType[]) this.keys; - final VType[] values = (VType[]) this.values; - for (int slot = 0; slot <= mask; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(null)) { - hasEmptyKey = false; - values[mask + 1] = null; - } - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public VType get(KType key) { - if (((key) == null)) { - return hasEmptyKey ? (VType) values[mask + 1] : null; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return (VType) values[slot]; - } - slot = (slot + 1) & mask; - } - - return null; - } - } - - /** {@inheritDoc} */ - @Override - public VType getOrDefault(KType key, VType defaultValue) { - if (((key) == null)) { - return hasEmptyKey ? (VType) values[mask + 1] : defaultValue; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return (VType) values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(KType key) { - if (((key) == null)) { - return hasEmptyKey; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(KType key) { - final int mask = this.mask; - if (((key) == null)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public VType indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return (VType) values[index]; - } - - /** {@inheritDoc} */ - @Override - public VType indexReplace(int index, VType newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - VType previousValue = (VType) values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, KType key, VType value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == null)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == null); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public VType indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - VType previousValue = (VType) values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = null; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, null); - - Arrays.fill(values, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ObjectObjectCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Equality comparison is - * performed with this object's {@link #equals(Object, Object)} method. Values are compared using - * {@link Objects#equals(Object)} method. - */ - protected boolean equalElements(ObjectObjectHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ObjectObjectCursor c : other) { - KType key = (KType) c.key; - if (!containsKey(key) || !java.util.Objects.equals(c.value, get(key))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final KType[] prevKeys = (KType[]) this.keys; - final VType[] prevValues = (VType[]) this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ObjectObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectObjectCursor fetch() { - final int mask = ObjectObjectHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = (VType) values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = null; - cursor.value = (VType) values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final KType[] keys = (KType[]) this.keys; - final VType[] values = (VType[]) this.values; - - if (hasEmptyKey) { - procedure.apply(null, (VType) values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final KType[] keys = (KType[]) this.keys; - final VType[] values = (VType[]) this.values; - - if (hasEmptyKey) { - if (!predicate.apply(null, (VType) values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final ObjectObjectHashMap owner = ObjectObjectHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectObjectProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectObjectPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final KType e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ObjectObjectHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = null; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ObjectCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractObjectCollection { - private final ObjectObjectHashMap owner = ObjectObjectHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(VType value) { - for (ObjectObjectCursor c : owner) { - if (java.util.Objects.equals(value, c.value)) { - return true; - } - } - return false; - } - - @Override - public > T forEach(T procedure) { - for (ObjectObjectCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - for (ObjectObjectCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator> iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final VType e) { - return owner.removeAll((key, value) -> java.util.Objects.equals(e, value)); - } - - @Override - public int removeAll(final ObjectPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ObjectObjectHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!(((KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = (VType) values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = (VType) values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ObjectObjectHashMap clone() { - try { - - ObjectObjectHashMap cloned = (ObjectObjectHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ObjectObjectCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectObjectHashMap from( - KType[] keys, VType[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectObjectHashMap map = new ObjectObjectHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(KType[] fromKeys, VType[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final KType[] keys = (KType[]) this.keys; - final VType[] values = (VType[]) this.values; - final int mask = this.mask; - KType existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == null)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == null)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - KType[] prevKeys = (KType[]) this.keys; - VType[] prevValues = (VType[]) this.values; - try { - int emptyElementSlot = 1; - this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); - this.values = ((VType[]) new Object[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, KType pendingKey, VType pendingValue) { - assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final KType[] prevKeys = (KType[]) this.keys; - final VType[] prevValues = (VType[]) this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final KType[] keys = (KType[]) this.keys; - final VType[] values = (VType[]) this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final KType existing = keys[slot]; - if (((existing) == null)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = null; - values[gapSlot] = null; - assigned--; - } - - protected boolean equals(Object v1, Object v2) { - return (v1 == v2) || (v1 != null && v1.equals(v2)); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectObjectIdentityHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectObjectIdentityHashMap.java deleted file mode 100644 index c726faa1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectObjectIdentityHashMap.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; - -/** An identity hash map of Object to Object. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeIdentityHashMap.java") -public class ObjectObjectIdentityHashMap extends ObjectObjectHashMap { - /** New instance with sane defaults. */ - public ObjectObjectIdentityHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectObjectIdentityHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectObjectIdentityHashMap(int expectedElements, double loadFactor) { - super(expectedElements, loadFactor); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectObjectIdentityHashMap( - ObjectObjectAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - @Override - public int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(System.identityHashCode(key)); - } - - @Override - public boolean equals(Object v1, Object v2) { - return v1 == v2; - } - - @SuppressWarnings("unchecked") - @Override - protected boolean equalElements(ObjectObjectHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ObjectObjectCursor c : other) { - KType key = (KType) c.key; - if (!containsKey(key) - || !equals(c.value, get(key))) { // Compare values using the same function as keys. - return false; - } - } - - return true; - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectObjectIdentityHashMap from( - KType[] keys, VType[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectObjectIdentityHashMap map = new ObjectObjectIdentityHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectObjectMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectObjectMap.java deleted file mode 100644 index c1316b06..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectObjectMap.java +++ /dev/null @@ -1,183 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectObjectCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ObjectObjectMap - extends ObjectObjectAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public VType get(KType key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public VType getOrDefault(KType key, VType defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public VType put(KType key, VType value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(KType key, VType value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ObjectObjectAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll( - Iterable> iterable); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public VType remove(KType key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ObjectObjectMap} and both objects contains exactly the - * same key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(KType key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexReplace(int index, VType newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, KType key, VType value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectSet.java b/sources/main/java/com/carrotsearch/hppc/ObjectSet.java deleted file mode 100644 index 24355d4d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectSet.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** A set of Objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java") -public interface ObjectSet extends ObjectCollection { - /** - * Adds k to the set. - * - * @return Returns true if this element was not part of the set before. Returns - * false if an equal element is already part of the set, does not replace the - * existing element with the argument. - */ - public boolean add(KType k); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); - - /** - * Adds all elements from the given {@link ObjectContainer} to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - * @since 0.9.1 - */ - public int addAll(ObjectContainer container); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectShortAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ObjectShortAssociativeContainer.java deleted file mode 100644 index a5c46c27..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectShortAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ObjectContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ObjectShortAssociativeContainer extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(KType key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ObjectShortPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectShortProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ObjectShortPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ObjectCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ShortContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectShortHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectShortHashMap.java deleted file mode 100644 index 9d492a11..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectShortHashMap.java +++ /dev/null @@ -1,1089 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of Object to short, implemented using open addressing with - * linear probing for collision resolution. Supports null key. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ObjectShortHashMap - implements ObjectShortMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public Object[] keys; - - /** The array holding values. */ - public short[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ObjectShortHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectShortHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectShortHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectShortHashMap(ObjectShortAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public short put(KType key, short value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == null)) { - short previousValue = hasEmptyKey ? values[mask + 1] : ((short) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final short previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ObjectShortAssociativeContainer container) { - final int count = size(); - for (ObjectShortCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (ObjectShortCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public short putOrAdd(KType key, short putValue, short incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((short) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public short addTo(KType key, short incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public short remove(KType key) { - final int mask = this.mask; - if (((key) == null)) { - if (!hasEmptyKey) { - return ((short) 0); - } - hasEmptyKey = false; - short previousValue = values[mask + 1]; - values[mask + 1] = ((short) 0); - return previousValue; - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - final short previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ObjectLookupContainer) { - if (hasEmptyKey && other.contains(null)) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ObjectCursor c : other) { - remove((KType) c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectShortPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(null, values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - } - - final KType[] keys = (KType[]) this.keys; - final short[] values = this.values; - for (int slot = 0; slot <= mask; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ObjectPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(null)) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - } - - final KType[] keys = (KType[]) this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - KType existing; - if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public short get(KType key) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : ((short) 0); - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public short getOrDefault(KType key, short defaultValue) { - if (((key) == null)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(KType key) { - if (((key) == null)) { - return hasEmptyKey; - } else { - final KType[] keys = (KType[]) this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(KType key) { - final int mask = this.mask; - if (((key) == null)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final KType[] keys = (KType[]) this.keys; - int slot = hashKey(key) & mask; - - KType existing; - while (!((existing = keys[slot]) == null)) { - if (this.equals(key, existing)) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public short indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public short indexReplace(int index, short newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - short previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, KType key, short value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == null)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == null); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public short indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - short previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((short) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ObjectShortCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Equality comparison is - * performed with this object's {@link #equals(Object, Object)} method. - */ - protected boolean equalElements(ObjectShortHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ObjectShortCursor c : other) { - KType key = (KType) c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final KType[] prevKeys = (KType[]) this.keys; - final short[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ObjectShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectShortCursor fetch() { - final int mask = ObjectShortHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = null; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final KType[] keys = (KType[]) this.keys; - final short[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(null, values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final KType[] keys = (KType[]) this.keys; - final short[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(null, values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == null)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final ObjectShortHashMap owner = ObjectShortHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectShortProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectShortPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final KType e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ObjectShortHashMap.this.mask; - while (index <= mask) { - KType existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = (KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = null; - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ShortCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractShortCollection { - private final ObjectShortHashMap owner = ObjectShortHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(short value) { - for (ObjectShortCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ObjectShortCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ObjectShortCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final short e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final ShortPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ObjectShortHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!(((KType) keys[slot]) == null)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ObjectShortHashMap clone() { - try { - - ObjectShortHashMap cloned = (ObjectShortHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ObjectShortCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectShortHashMap from(KType[] keys, short[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectShortHashMap map = new ObjectShortHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(KType[] fromKeys, short[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final KType[] keys = (KType[]) this.keys; - final short[] values = this.values; - final int mask = this.mask; - KType existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == null)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == null)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - KType[] prevKeys = (KType[]) this.keys; - short[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); - this.values = (new short[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, KType pendingKey, short pendingValue) { - assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final KType[] prevKeys = (KType[]) this.keys; - final short[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final KType[] keys = (KType[]) this.keys; - final short[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final KType existing = keys[slot]; - if (((existing) == null)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = null; - values[gapSlot] = ((short) 0); - assigned--; - } - - protected boolean equals(Object v1, Object v2) { - return (v1 == v2) || (v1 != null && v1.equals(v2)); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectShortIdentityHashMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectShortIdentityHashMap.java deleted file mode 100644 index c5c04c28..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectShortIdentityHashMap.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -/** An identity hash map of Object to short. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeIdentityHashMap.java") -public class ObjectShortIdentityHashMap extends ObjectShortHashMap { - /** New instance with sane defaults. */ - public ObjectShortIdentityHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectShortIdentityHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ObjectShortIdentityHashMap(int expectedElements, double loadFactor) { - super(expectedElements, loadFactor); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ObjectShortIdentityHashMap(ObjectShortAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - @Override - public int hashKey(KType key) { - assert !((key) == null); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(System.identityHashCode(key)); - } - - @Override - public boolean equals(Object v1, Object v2) { - return v1 == v2; - } - - @SuppressWarnings("unchecked") - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ObjectShortIdentityHashMap from(KType[] keys, short[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ObjectShortIdentityHashMap map = new ObjectShortIdentityHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectShortMap.java b/sources/main/java/com/carrotsearch/hppc/ObjectShortMap.java deleted file mode 100644 index df88b9e2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectShortMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectShortCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ObjectShortMap extends ObjectShortAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public short get(KType key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public short getOrDefault(KType key, short defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public short put(KType key, short value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(KType key, short value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ObjectShortAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public short putOrAdd(KType key, short putValue, short incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public short addTo(KType key, short additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public short remove(KType key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ObjectShortMap} and both objects contains exactly the - * same key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(KType key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexReplace(int index, short newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, KType key, short value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ObjectStack.java b/sources/main/java/com/carrotsearch/hppc/ObjectStack.java deleted file mode 100644 index d768be98..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ObjectStack.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ObjectCursor; -import java.util.Arrays; - -/** - * A subclass of {@link ObjectArrayList} adding stack-related utility methods. The top of the stack - * is at the {@link #size()} - 1 element. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") -public class ObjectStack extends ObjectArrayList { - /** New instance with sane defaults. */ - public ObjectStack() { - super(); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ObjectStack(int expectedElements) { - super(expectedElements); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public ObjectStack(int expectedElements, ArraySizingStrategy resizer) { - super(expectedElements, resizer); - } - - /** Create a stack by pushing all elements of another container to it. */ - public ObjectStack(ObjectContainer container) { - super(container); - } - - /** Adds one Object to the stack. */ - public void push(KType e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** Adds two Objects to the stack. */ - public void push(KType e1, KType e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Adds three Objects to the stack. */ - public void push(KType e1, KType e2, KType e3) { - ensureBufferSpace(3); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - } - - /** Adds four Objects to the stack. */ - public void push(KType e1, KType e2, KType e3, KType e4) { - ensureBufferSpace(4); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - buffer[elementsCount++] = e4; - } - - /** Add a range of array elements to the stack. */ - public void push(KType[] elements, int start, int len) { - assert start >= 0 && len >= 0; - - ensureBufferSpace(len); - System.arraycopy(elements, start, buffer, elementsCount, len); - elementsCount += len; - } - - /** - * Vararg-signature method for pushing elements at the top of the stack. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - @SafeVarargs - public final void push(KType... elements) { - push(elements, 0, elements.length); - } - - /** Pushes all elements from another container to the top of the stack. */ - public int pushAll(ObjectContainer container) { - return addAll(container); - } - - /** Pushes all elements from another iterable to the top of the stack. */ - public int pushAll(Iterable> iterable) { - return addAll(iterable); - } - - /** Discard an arbitrary number of elements from the top of the stack. */ - public void discard(int count) { - assert elementsCount >= count; - - elementsCount -= count; - - Arrays.fill(buffer, elementsCount, elementsCount + count, null); - } - - /** Discard the top element from the stack. */ - public void discard() { - assert elementsCount > 0; - - elementsCount--; - - buffer[elementsCount] = null; - } - - /** Remove the top element from the stack and return it. */ - public KType pop() { - return removeLast(); - } - - /** Peek at the top element on the stack. */ - public KType peek() { - assert elementsCount > 0; - return (KType) buffer[elementsCount - 1]; - } - - /** Create a stack by pushing a variable number of arguments to it. */ - @SafeVarargs - public static ObjectStack from(KType... elements) { - final ObjectStack stack = new ObjectStack(elements.length); - stack.push(elements); - return stack; - } - - /** {@inheritDoc} */ - @Override - public ObjectStack clone() { - return (ObjectStack) super.clone(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/PgmIndexUtil.java b/sources/main/java/com/carrotsearch/hppc/PgmIndexUtil.java deleted file mode 100644 index 9793ab2b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/PgmIndexUtil.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -/** Utility methods for {@code KTypePgmIndex}. */ -final class PgmIndexUtil { - - /** Adds the first key of the current segment to the segment data bytes. */ - static void addKey(KType key, IntArrayList segmentData) { - throw new UnsupportedOperationException("Invalid for generic type: " + key); - } - - /** Adds the first key of the current segment to the segment data bytes. */ - static void addKey(int key, IntArrayList segmentData) { - segmentData.add(key); - } - - /** Adds the first key of the current segment to the segment data bytes. */ - static void addKey(float key, IntArrayList segmentData) { - addKey(Float.floatToIntBits(key), segmentData); - } - - /** Adds the first key of the current segment to the segment data bytes. */ - static void addKey(long key, IntArrayList segmentData) { - segmentData.add((int) key); - segmentData.add((int) (key >> 32)); - } - - /** Adds the first key of the current segment to the segment data bytes. */ - static void addKey(double key, IntArrayList segmentData) { - addKey(Double.doubleToRawLongBits(key), segmentData); - } - - /** Gets the first key of the segment at the given data index. */ - static KType getKey(int segmentDataIndex, int[] segmentData, KType keyType) { - throw new UnsupportedOperationException("Invalid for generic type: " + keyType); - } - - /** Gets the first key of the segment at the given data index. */ - static int getKey(int segmentDataIndex, int[] segmentData, int keyType) { - return segmentData[segmentDataIndex]; - } - - /** Gets the first key of the segment at the given data index. */ - static float getKey(int segmentDataIndex, int[] segmentData, float keyType) { - return Float.intBitsToFloat(getKey(segmentDataIndex, segmentData, 0)); - } - - /** Gets the first key of the segment at the given data index. */ - static long getKey(int segmentDataIndex, int[] segmentData, long keyType) { - return (segmentData[segmentDataIndex] & 0xFFFFFFFFL) - | (((long) segmentData[segmentDataIndex + 1]) << 32); - } - - /** Gets the first key of the segment at the given data index. */ - static double getKey(int segmentDataIndex, int[] segmentData, double keyType) { - return Double.longBitsToDouble(getKey(segmentDataIndex, segmentData, 0L)); - } - - /** - * Adds the intercept of the current segment to the segment data bytes. The intercept is stored as - * an int for a key size equal to 1, otherwise it is stored as a long. - * - * @param keySize The size of the key, measure in {@link Integer#BYTES}. - */ - static void addIntercept(long intercept, IntArrayList segmentData, int keySize) { - assert keySize >= 1 && keySize <= 2; - if (keySize == 1) { - addKey((int) intercept, segmentData); - } else { - addKey(intercept, segmentData); - } - } - - /** - * Gets the intercept of the segment at the given data index. - * - * @param keySize The size of the key, measure in {@link Integer#BYTES}. - */ - static long getIntercept(int segmentDataIndex, int[] segmentData, int keySize) { - assert keySize >= 1 && keySize <= 2; - if (keySize == 1) { - return getKey(segmentDataIndex, segmentData, 0); - } - return getKey(segmentDataIndex, segmentData, 0L); - } - - /** - * Adds the slope of the current segment to the segment data bytes. The intercept is stored as a - * float for a key size equal to 1, otherwise it is stored as a double. - * - * @param keySize The size of the key, measure in {@link Integer#BYTES}. - */ - static void addSlope(double slope, IntArrayList segmentData, int keySize) { - assert keySize >= 1 && keySize <= 2; - if (keySize == 1) { - addKey((float) slope, segmentData); - } else { - addKey(slope, segmentData); - } - } - - /** - * Gets the slope of the segment at the given data index. - * - * @param keySize The size of the key, measure in {@link Integer#BYTES}. - */ - static double getSlope(int segmentDataIndex, int[] segmentData, int keySize) { - assert keySize >= 1 && keySize <= 2; - if (keySize == 1) { - return getKey(segmentDataIndex, segmentData, 0f); - } - return getKey(segmentDataIndex, segmentData, 0d); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/PlaModel.java b/sources/main/java/com/carrotsearch/hppc/PlaModel.java deleted file mode 100644 index 49317404..00000000 --- a/sources/main/java/com/carrotsearch/hppc/PlaModel.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import java.util.Arrays; - -/** - * Optimal Piecewise Linear Approximation Model for KType keys. - * - *

Learns a mapping that returns a position for a KType key which is at most epsilon - * away from the correct one in a sorted list of keys. It is optimal and piecewise because it learns - * the minimum number of epsilon-approximate segments. - * - *

The PLA-model consists of a sequence segments. A segment s is a triple (key,slope,intercept) - * that indexes a range of keys through the function fs(k) = k × slope + intercept, which provides - * an epsilon-approximation of the position of the key k. - */ -public class PlaModel implements Accountable { - - /** Initial capacity of the lower and upper point lists. */ - private static final int INITIAL_CAPACITY = 1 << 8; - - /** Epsilon precision of the PLA-model. */ - private int epsilon; - - /** First key of the current segment. */ - private double firstKey; - - /** Previous key used to check that keys are added in strictly increasing sequence. */ - private double previousKey; - - /** Number of points in the convex hull for the current segment. */ - private int numPointsInHull; - - /** Enclosing rectangle for the current segment. */ - private final Point[] rect = new Point[4]; - - /** - * Ordered list of lower points for the current segment. Inside the list, allocated points are - * re-used. - */ - private final PointList lower = new PointList(INITIAL_CAPACITY); - - /** - * Ordered list of upper points for the current segment. Inside the list, allocated points are - * re-used. - */ - private final PointList upper = new PointList(INITIAL_CAPACITY); - - /** Index of the first lower point to compare to. */ - private int lowerStart; - - /** Index of the first upper point to compare to. */ - private int upperStart; - - // Re-used mutable points and slopes. - private final Point point1 = new Point(); - private final Point point2 = new Point(); - private final Slope slope1 = new Slope(); - private final Slope slope2 = new Slope(); - private final Slope slopeTmp = new Slope(); - private final Slope slopeMin = new Slope(); - private final Slope slopeMax = new Slope(); - - /** - * Creates an optimal PLA-model with the provided epsilon precision. - * - * @param epsilon must be greater than or equal to 0. - */ - public PlaModel(int epsilon) { - setEpsilon(epsilon); - for (int i = 0; i < rect.length; i++) { - rect[i] = new Point(); - } - reset(); - } - - /** Sets epsilon precision which must be greater than or equal to 0. */ - public void setEpsilon(int epsilon) { - if (epsilon < 0) { - throw new IllegalArgumentException("epsilon must be >= 0"); - } - this.epsilon = epsilon; - } - - private void reset() { - previousKey = Double.NEGATIVE_INFINITY; - numPointsInHull = 0; - lower.clear(); - upper.clear(); - } - - /** - * Adds a key to this PLA-model. The keys must be provided in a strictly increasing sequence. That - * is, the key must be greater than the previous key. - * - * @param index The index of the key in the sorted key list. - * @param segmentConsumer The consumer to call when a new segment is built in the PLA-model. - */ - public void addKey(double key, int index, SegmentConsumer segmentConsumer) { - if (key <= previousKey) { - throw new IllegalArgumentException("Keys must be increasing"); - } - previousKey = key; - point1.set(key, addEpsilon(index)); - point2.set(key, subtractEpsilon(index)); - - if (numPointsInHull > 1) { - slope1.set(rect[0], rect[2]); - slope2.set(rect[1], rect[3]); - boolean outside_line1 = slopeTmp.set(rect[2], point1).isLessThan(slope1); - boolean outside_line2 = slopeTmp.set(rect[3], point2).isGreaterThan(slope2); - if (outside_line1 || outside_line2) { - produceSegment(segmentConsumer); - numPointsInHull = 0; - } - } - if (numPointsInHull == 0) { - firstKey = key; - rect[0].set(point1); - rect[1].set(point2); - upper.clear(); - lower.clear(); - upper.add(point1); - lower.add(point2); - upperStart = lowerStart = 0; - numPointsInHull++; - return; - } - if (numPointsInHull == 1) { - rect[2].set(point2); - rect[3].set(point1); - upper.add(point1); - lower.add(point2); - numPointsInHull++; - return; - } - - if (slopeTmp.set(rect[1], point1).isLessThan(slope2)) { - // Find extreme slope. - slopeMin.set(point1, lower.get(lowerStart)); - int min_i = lowerStart; - for (int i = lowerStart + 1; i < lower.size(); i++) { - slopeTmp.set(point1, lower.get(i)); - if (slopeTmp.isGreaterThan(slopeMin)) { - break; - } - slopeMin.set(slopeTmp); - min_i = i; - } - rect[1].set(lower.get(min_i)); - rect[3].set(point1); - lowerStart = min_i; - - // Hull update. - int end = upper.size(); - while (end >= upperStart + 2 && cross(upper.get(end - 2), upper.get(end - 1), point1) <= 0) { - end--; - } - upper.clearFrom(end); - upper.add(point1); - } - - if (slopeTmp.set(rect[0], point2).isGreaterThan(slope1)) { - // Find extreme slope. - slopeMax.set(point2, upper.get(upperStart)); - int max_i = upperStart; - for (int i = upperStart + 1; i < upper.size(); i++) { - slopeTmp.set(point2, upper.get(i)); - if (slopeTmp.isLessThan(slopeMax)) { - break; - } - slopeMax.set(slopeTmp); - max_i = i; - } - rect[0].set(upper.get(max_i)); - rect[2].set(point2); - upperStart = max_i; - - // Hull update. - int end = lower.size(); - while (end >= lowerStart + 2 && cross(lower.get(end - 2), lower.get(end - 1), point2) >= 0) { - end--; - } - lower.clearFrom(end); - lower.add(point2); - } - - numPointsInHull++; - } - - private void produceSegment(SegmentConsumer segmentConsumer) { - double slope; - long intercept; - - if (numPointsInHull == 1) { - slope = 0d; - intercept = ((long) rect[0].y + rect[1].y) >>> 1; - - } else { - Point p0 = rect[0]; - Point p1 = rect[1]; - Point p2 = rect[2]; - Point p3 = rect[3]; - - // Compute the slope intersection point. - double intersectX; - double intersectY; - slope1.set(p0, p2); - slope2.set(p1, p3); - if (slope1.isEqual(slope2)) { - intersectX = p0.x; - intersectY = p0.y; - } else { - slopeTmp.set(p0, p1); - double a = slope1.dx * slope2.dy - slope1.dy * slope2.dx; - double b = (slopeTmp.dx * slope2.dy - slopeTmp.dy * slope2.dx) / a; - intersectX = p0.x + b * slope1.dx; - intersectY = p0.y + b * slope1.dy; - } - - // Compute the slope range. - double minSlope = Slope.asDouble(p0, p2); - double maxSlope = Slope.asDouble(p1, p3); - - // Compute the segment slope and intercept. - slope = (minSlope + maxSlope) / 2d; - intercept = (long) (intersectY - (intersectX - firstKey) * slope); - } - - segmentConsumer.accept(firstKey, slope, intercept); - } - - /** - * Finishes the PLA-model construction. Declares that no additional keys will be added. Builds the - * last segment and calls the provided {@link SegmentConsumer}. - */ - public void finish(SegmentConsumer segmentConsumer) { - produceSegment(segmentConsumer); - reset(); - } - - @Override - public long ramBytesAllocated() { - // int: epsilon, numPointsInHull, lowerStart, upperStart - // double: firstKey, previousKey - // Point: rect[4], point1, point2 - // Slope: slope1, slope2, slopeTmp, slopeMin, slopeMax - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + 2 * Double.BYTES - + 6L * Point.RAM_BYTES_ALLOCATED - + lower.ramBytesAllocated() - + upper.ramBytesAllocated() - + 5L * Slope.RAM_BYTES_ALLOCATED; - } - - @Override - public long ramBytesUsed() { - return ramBytesAllocated(); - } - - private int addEpsilon(int index) { - try { - return Math.addExact(index, epsilon); - } catch (ArithmeticException e) { - return Integer.MAX_VALUE; - } - } - - private int subtractEpsilon(int index) { - try { - return Math.subtractExact(index, epsilon); - } catch (ArithmeticException e) { - return Integer.MIN_VALUE; - } - } - - private static double cross(Point o, Point a, Point b) { - return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x); - } - - /** Consumer notified when a new segment is built by the {@link PlaModel}. */ - public interface SegmentConsumer { - - /** - * Consumes a new segment. The segment is defined by the epsilon-approximation function fs(k) = - * k × slope + intercept. - * - * @param firstKey The first key of the segment. - * @param slope The segment slope. - * @param intercept The segment intercept. - */ - void accept(double firstKey, double slope, long intercept); - } - - /** Re-usable mutable (x,y) point. */ - private static class Point { - - static final int RAM_BYTES_ALLOCATED = - RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + Double.BYTES + Long.BYTES; - - double x; - long y; - - Point set(double x, long y) { - this.x = x; - this.y = y; - return this; - } - - Point set(Point p) { - return set(p.x, p.y); - } - } - - /** List of mutable {@link Point}. Re-uses allocated points instead of creating new instances. */ - private static class PointList implements Accountable { - - Point[] points; - int size; - int numAllocated; - - PointList(int initialCapacity) { - points = new Point[initialCapacity]; - } - - void add(Point point) { - if (size == points.length) { - int newSize = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE.grow(points.length, size, 1); - points = Arrays.copyOf(points, newSize); - } - if (size == numAllocated) { - points[numAllocated++] = new Point(); - } - points[size++].set(point); - } - - Point get(int index) { - return points[index]; - } - - int size() { - return size; - } - - void clear() { - size = 0; - } - - void clearFrom(int end) { - size = end; - } - - @Override - public long ramBytesAllocated() { - // int: size, numAllocated - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 2 * Integer.BYTES - + RamUsageEstimator.shallowSizeOfArray(points) - + (long) numAllocated * Point.RAM_BYTES_ALLOCATED; - } - - @Override - public long ramBytesUsed() { - return ramBytesAllocated(); - } - } - - /** Re-usable mutable (dx,dy) slope. */ - private static class Slope { - - static final int RAM_BYTES_ALLOCATED = - RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + Double.BYTES + Long.BYTES; - - double dx; - long dy; - - void set(Slope s) { - dx = s.dx; - dy = s.dy; - } - - Slope set(Point p1, Point p2) { - dx = p2.x - p1.x; - dy = p2.y - p1.y; - return this; - } - - boolean isLessThan(Slope s) { - return dy * s.dx < dx * s.dy; - } - - boolean isGreaterThan(Slope s) { - return dy * s.dx > dx * s.dy; - } - - boolean isEqual(Slope s) { - return Double.doubleToLongBits(dy * s.dx) == Double.doubleToLongBits(dx * s.dy); - } - - static double asDouble(Point p1, Point p2) { - return (double) (p2.y - p1.y) / (p2.x - p1.x); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/Preallocable.java b/sources/main/java/com/carrotsearch/hppc/Preallocable.java deleted file mode 100644 index 1251bcb9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/Preallocable.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -/** Anything that can preallocate buffers given prior knowledge of the number of stored elements. */ -public interface Preallocable { - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - public void ensureCapacity(int expectedElements); -} diff --git a/sources/main/java/com/carrotsearch/hppc/RamUsageEstimator.java b/sources/main/java/com/carrotsearch/hppc/RamUsageEstimator.java deleted file mode 100644 index 907ea2e9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/RamUsageEstimator.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.Map; - -/** - * Helper class that helps estimate memory usage - * - *

Mostly forked from Lucene tag releases/lucene-solr/8.5.1 - */ -final class RamUsageEstimator { - /** No instantiation. */ - private RamUsageEstimator() {} - - /** True, iff compressed references (oops) are enabled by this JVM */ - static final boolean COMPRESSED_REFS_ENABLED; - - /** Number of bytes this JVM uses to represent an object reference. */ - static final int NUM_BYTES_OBJECT_REF; - - /** Number of bytes to represent an object header (no fields, no alignments). */ - static final int NUM_BYTES_OBJECT_HEADER; - - /** Number of bytes to represent an array header (no content, but with alignments). */ - static final int NUM_BYTES_ARRAY_HEADER; - - /** - * A constant specifying the object alignment boundary inside the JVM. Objects will always take a - * full multiple of this constant, possibly wasting some space. - */ - static final int NUM_BYTES_OBJECT_ALIGNMENT; - - /** Sizes of primitive classes. */ - static final Map, Integer> primitiveSizes; - - static { - Map, Integer> primitiveSizesMap = new IdentityHashMap<>(); - primitiveSizesMap.put(boolean.class, 1); - primitiveSizesMap.put(byte.class, 1); - primitiveSizesMap.put(char.class, Character.BYTES); - primitiveSizesMap.put(short.class, Short.BYTES); - primitiveSizesMap.put(int.class, Integer.BYTES); - primitiveSizesMap.put(float.class, Float.BYTES); - primitiveSizesMap.put(double.class, Double.BYTES); - primitiveSizesMap.put(long.class, Long.BYTES); - - primitiveSizes = Collections.unmodifiableMap(primitiveSizesMap); - } - - static final boolean JRE_IS_64BIT; - - static final String MANAGEMENT_FACTORY_CLASS = "java.lang.management.ManagementFactory"; - static final String HOTSPOT_BEAN_CLASS = "com.sun.management.HotSpotDiagnosticMXBean"; - - static final String OS_ARCH = System.getProperty("os.arch"); - - // Initialize constants and try to collect information about the JVM internals. - static { - boolean is64Bit = false; - String datamodel = null; - try { - datamodel = System.getProperty("sun.arch.data.model"); - if (datamodel != null) { - is64Bit = datamodel.contains("64"); - } - } catch (SecurityException ignored) { - } - if (datamodel == null) { - is64Bit = OS_ARCH != null && OS_ARCH.contains("64"); - } - JRE_IS_64BIT = is64Bit; - if (JRE_IS_64BIT) { - // Try to get compressed oops and object alignment (the default seems to be 8 on Hotspot); - // (this only works on 64 bit, on 32 bits the alignment and reference size is fixed): - boolean compressedOops = false; - int objectAlignment = 8; - try { - final Class beanClazz = Class.forName(HOTSPOT_BEAN_CLASS); - // we use reflection for this, because the management factory is not part - // of Java 8's compact profile: - final Object hotSpotBean = - Class.forName(MANAGEMENT_FACTORY_CLASS) - .getMethod("getPlatformMXBean", Class.class) - .invoke(null, beanClazz); - if (hotSpotBean != null) { - final Method getVMOptionMethod = beanClazz.getMethod("getVMOption", String.class); - try { - final Object vmOption = getVMOptionMethod.invoke(hotSpotBean, "UseCompressedOops"); - compressedOops = - Boolean.parseBoolean( - vmOption.getClass().getMethod("getValue").invoke(vmOption).toString()); - } catch (ReflectiveOperationException | RuntimeException ignored) { - } - try { - final Object vmOption = getVMOptionMethod.invoke(hotSpotBean, "ObjectAlignmentInBytes"); - objectAlignment = - Integer.parseInt( - vmOption.getClass().getMethod("getValue").invoke(vmOption).toString()); - } catch (ReflectiveOperationException | RuntimeException ignored) { - } - } - } catch (ReflectiveOperationException | RuntimeException ignored) { - } - COMPRESSED_REFS_ENABLED = compressedOops; - NUM_BYTES_OBJECT_ALIGNMENT = objectAlignment; - // reference size is 4, if we have compressed oops: - NUM_BYTES_OBJECT_REF = COMPRESSED_REFS_ENABLED ? 4 : 8; - // "best guess" based on reference size: - NUM_BYTES_OBJECT_HEADER = 8 + NUM_BYTES_OBJECT_REF; - // array header is NUM_BYTES_OBJECT_HEADER + NUM_BYTES_INT, but aligned (object alignment): - NUM_BYTES_ARRAY_HEADER = (int) alignObjectSize(NUM_BYTES_OBJECT_HEADER + Integer.BYTES); - } else { - COMPRESSED_REFS_ENABLED = false; - NUM_BYTES_OBJECT_ALIGNMENT = 8; - NUM_BYTES_OBJECT_REF = 4; - NUM_BYTES_OBJECT_HEADER = 8; - // For 32 bit JVMs, no extra alignment of array header: - NUM_BYTES_ARRAY_HEADER = NUM_BYTES_OBJECT_HEADER + Integer.BYTES; - } - } - - /** Aligns an object size to be the next multiple of {@link #NUM_BYTES_OBJECT_ALIGNMENT}. */ - static long alignObjectSize(long size) { - size += (long) NUM_BYTES_OBJECT_ALIGNMENT - 1L; - return size - (size % NUM_BYTES_OBJECT_ALIGNMENT); - } - - /** - * Return used part of shallow size of any array. - * - * @param usedSize Size that array is actually used - */ - static long shallowUsedSizeOfArray(Object array, int usedSize) { - long size = NUM_BYTES_ARRAY_HEADER; - if (usedSize > 0) { - Class arrayElementClazz = array.getClass().getComponentType(); - if (arrayElementClazz.isPrimitive()) { - size += (long) usedSize * primitiveSizes.get(arrayElementClazz); - } else { - size += (long) NUM_BYTES_OBJECT_REF * usedSize; - } - } - return alignObjectSize(size); - } - - /** Return shallow size of any array. */ - static long shallowSizeOfArray(Object array) { - return shallowUsedSizeOfArray(array, Array.getLength(array)); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortArrayDeque.java b/sources/main/java/com/carrotsearch/hppc/ShortArrayDeque.java deleted file mode 100644 index 9c1cf824..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortArrayDeque.java +++ /dev/null @@ -1,776 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.ShortCursor; -import com.carrotsearch.hppc.predicates.ShortPredicate; -import com.carrotsearch.hppc.procedures.ShortProcedure; -import java.util.*; - -/** An array-backed {@link ShortDeque}. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") -public class ShortArrayDeque extends AbstractShortCollection - implements ShortDeque, Preallocable, Cloneable, Accountable { - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** Internal array for storing elements of the deque. */ - public short[] buffer = ShortArrayList.EMPTY_ARRAY; - - /** - * The index of the element at the head of the deque or an arbitrary number equal to tail if the - * deque is empty. - */ - public int head; - - /** The index at which the next element would be added to the tail of the deque. */ - public int tail; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public ShortArrayDeque() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortArrayDeque(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public ShortArrayDeque(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - ensureCapacity(expectedElements); - } - - /** - * Creates a new deque from elements of another container, appending elements at the end of the - * deque in the iteration order. - */ - public ShortArrayDeque(ShortContainer container) { - this(container.size()); - addLast(container); - } - - /** {@inheritDoc} */ - @Override - public void addFirst(short e1) { - int h = oneLeft(head, buffer.length); - if (h == tail) { - ensureBufferSpace(1); - h = oneLeft(head, buffer.length); - } - buffer[head = h] = e1; - } - - /** - * Vararg-signature method for adding elements at the front of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to add. - */ - public final void addFirst(short... elements) { - ensureBufferSpace(elements.length); - for (short k : elements) { - addFirst(k); - } - } - - /** - * Inserts all elements from the given container to the front of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(ShortContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (ShortCursor cursor : container) { - addFirst(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the front of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addFirst(Iterable iterable) { - int size = 0; - for (ShortCursor cursor : iterable) { - addFirst(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void addLast(short e1) { - int t = oneRight(tail, buffer.length); - if (head == t) { - ensureBufferSpace(1); - t = oneRight(tail, buffer.length); - } - buffer[tail] = e1; - tail = t; - } - - /** - * Vararg-signature method for adding elements at the end of this deque. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - * - * @param elements The elements to iterate over. - */ - public final void addLast(short... elements) { - ensureBufferSpace(1); - for (short k : elements) { - addLast(k); - } - } - - /** - * Inserts all elements from the given container to the end of this deque. - * - * @param container The container to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(ShortContainer container) { - int size = container.size(); - ensureBufferSpace(size); - - for (ShortCursor cursor : container) { - addLast(cursor.value); - } - - return size; - } - - /** - * Inserts all elements from the given iterable to the end of this deque. - * - * @param iterable The iterable to iterate over. - * @return Returns the number of elements actually added as a result of this call. - */ - public int addLast(Iterable iterable) { - int size = 0; - for (ShortCursor cursor : iterable) { - addLast(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public short removeFirst() { - assert size() > 0 : "The deque is empty."; - - final short result = buffer[head]; - buffer[head] = ((short) 0); - head = oneRight(head, buffer.length); - return result; - } - - /** {@inheritDoc} */ - @Override - public short removeLast() { - assert size() > 0 : "The deque is empty."; - - tail = oneLeft(tail, buffer.length); - final short result = buffer[tail]; - buffer[tail] = ((short) 0); - return result; - } - - /** {@inheritDoc} */ - @Override - public short getFirst() { - assert size() > 0 : "The deque is empty."; - - return buffer[head]; - } - - /** {@inheritDoc} */ - @Override - public short getLast() { - assert size() > 0 : "The deque is empty."; - - return buffer[oneLeft(tail, buffer.length)]; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(short e1) { - final int index = bufferIndexOf(e1); - if (index >= 0) removeAtBufferIndex(index); - return index; - } - - /** - * Return the index of the first (counting from head) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int bufferIndexOf(short e1) { - final int last = tail; - final int bufLen = buffer.length; - for (int i = head; i != last; i = oneRight(i, bufLen)) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(short e1) { - final int index = lastBufferIndexOf(e1); - if (index >= 0) { - removeAtBufferIndex(index); - } - return index; - } - - /** - * Return the index of the last (counting from tail) element equal to e1. The index - * points to the {@link #buffer} array. - * - * @param e1 The element to look for. - * @return Returns the index of the first element equal to e1 or -1 if - * not found. - */ - public int lastBufferIndexOf(short e1) { - final int bufLen = buffer.length; - final int last = oneLeft(head, bufLen); - for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { - if (((e1) == (buffer[i]))) return i; - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(short e1) { - int removed = 0; - final int last = tail; - final int bufLen = buffer.length; - int from, to; - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (((e1) == (buffer[from]))) { - buffer[from] = ((short) 0); - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((short) 0); - } - - to = oneRight(to, bufLen); - } - - tail = to; - return removed; - } - - /** - * Removes the element at index in the internal {#link {@link #buffer} array, - * returning its value. - * - * @param index Index of the element to remove. The index must be located between {@link #head} - * and {@link #tail} in modulo {@link #buffer} arithmetic. - */ - public void removeAtBufferIndex(int index) { - assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) - : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; - - // Cache fields in locals (hopefully moved to registers). - final short[] buffer = this.buffer; - final int bufLen = buffer.length; - final int lastIndex = bufLen - 1; - final int head = this.head; - final int tail = this.tail; - - final int leftChunk = Math.abs(index - head) % bufLen; - final int rightChunk = Math.abs(tail - index) % bufLen; - - if (leftChunk < rightChunk) { - if (index >= head) { - System.arraycopy(buffer, head, buffer, head + 1, leftChunk); - } else { - System.arraycopy(buffer, 0, buffer, 1, index); - buffer[0] = buffer[lastIndex]; - System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); - } - buffer[head] = ((short) 0); - this.head = oneRight(head, bufLen); - } else { - if (index < tail) { - System.arraycopy(buffer, index + 1, buffer, index, rightChunk); - } else { - System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); - buffer[lastIndex] = buffer[0]; - System.arraycopy(buffer, 1, buffer, 0, tail); - } - buffer[tail] = ((short) 0); - this.tail = oneLeft(tail, bufLen); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int size() { - if (head <= tail) return tail - head; - else return (tail - head + buffer.length); - } - - /** - * {@inheritDoc} - * - *

The internal array buffers are not released as a result of this call. - * - * @see #release() - */ - @Override - public void clear() { - if (head < tail) { - Arrays.fill(buffer, head, tail, ((short) 0)); - } else { - Arrays.fill(buffer, 0, tail, ((short) 0)); - Arrays.fill(buffer, head, buffer.length, ((short) 0)); - } - this.head = tail = 0; - } - - /** Release internal buffers of this deque and reallocate with the default buffer. */ - public void release() { - this.head = tail = 0; - buffer = ShortArrayList.EMPTY_ARRAY; - ensureBufferSpace(0); - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - ensureBufferSpace(expectedElements - size()); - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = buffer.length; - final int elementsCount = size(); - - if (elementsCount + expectedAdditions >= bufferLen) { - final int emptySlot = 1; // deque invariant: always an empty slot. - final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); - assert newSize >= (elementsCount + expectedAdditions + emptySlot) - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - try { - final short[] newBuffer = (new short[newSize]); - if (bufferLen > 0) { - toArray(newBuffer); - tail = elementsCount; - head = 0; - } - this.buffer = newBuffer; - } catch (OutOfMemoryError e) { - throw new BufferAllocationException( - "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); - } - } - } - - /** {@inheritDoc} */ - @Override - public short[] toArray() { - - final int size = size(); - return toArray((new short[size])); - } - - /** - * Copies elements of this deque to an array. The content of the target array is - * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). - * - * @param target The target array must be large enough to hold all elements. - * @return Returns the target argument for chaining. - */ - public short[] toArray(short[] target) { - assert target.length >= size() : "Target array must be >= " + size(); - - if (head < tail) { - // The contents is not wrapped around. Just copy. - System.arraycopy(buffer, head, target, 0, size()); - } else if (head > tail) { - // The contents is split. Merge elements from the following indexes: - // [head...buffer.length - 1][0, tail - 1] - final int rightCount = buffer.length - head; - System.arraycopy(buffer, head, target, 0, rightCount); - System.arraycopy(buffer, 0, target, rightCount, tail); - } - - return target; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public ShortArrayDeque clone() { - try { - - ShortArrayDeque cloned = (ShortArrayDeque) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Move one index to the left, wrapping around buffer. */ - protected static int oneLeft(int index, int modulus) { - if (index >= 1) { - return index - 1; - } - return modulus - 1; - } - - /** Move one index to the right, wrapping around buffer. */ - protected static int oneRight(int index, int modulus) { - if (index + 1 == modulus) { - return 0; - } - return index + 1; - } - - @Override - public long ramBytesAllocated() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: head, tail - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES * 2 - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); - } - - /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ - private final class ValueIterator extends AbstractIterator { - private final ShortCursor cursor; - private int remaining; - - public ValueIterator() { - cursor = new ShortCursor(); - cursor.index = oneLeft(head, buffer.length); - this.remaining = size(); - } - - @Override - protected ShortCursor fetch() { - if (remaining == 0) { - return done(); - } - - remaining--; - cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; - return cursor; - } - } - - /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ - private final class DescendingValueIterator extends AbstractIterator { - private final ShortCursor cursor; - private int remaining; - - public DescendingValueIterator() { - cursor = new ShortCursor(); - cursor.index = tail; - this.remaining = size(); - } - - @Override - protected ShortCursor fetch() { - if (remaining == 0) return done(); - - remaining--; - cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; - return cursor; - } - } - - /** - * Returns a cursor over the values of this deque (in head to tail order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *

-   * for (IntValueCursor c : intDeque) {
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator() { - return new ValueIterator(); - } - - /** - * Returns a cursor over the values of this deque (in tail to head order). The iterator is - * implemented as a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in - * the deque's buffer) use the cursor's public fields. An example is shown below. - * - *
-   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
-   *   final IntCursor c = i.next();
-   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator descendingIterator() { - return new DescendingValueIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - forEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, fromIndex, inclusive, to - * toIndex, exclusive. - */ - private void forEach(ShortProcedure procedure, int fromIndex, final int toIndex) { - final short[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - procedure.apply(buffer[i]); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - int fromIndex = head; - int toIndex = tail; - - final short[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (!predicate.apply(buffer[i])) { - break; - } - } - - return predicate; - } - - /** Applies procedure to all elements of this deque, tail to head. */ - @Override - public T descendingForEach(T procedure) { - descendingForEach(procedure, head, tail); - return procedure; - } - - /** - * Applies procedure to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive. - */ - private void descendingForEach(ShortProcedure procedure, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final short[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - procedure.apply(buffer[i]); - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public T descendingForEach(T predicate) { - descendingForEach(predicate, head, tail); - return predicate; - } - - /** - * Applies predicate to a slice of the deque, toIndex, exclusive, down - * to fromIndex, inclusive or until the predicate returns false. - */ - private void descendingForEach(ShortPredicate predicate, int fromIndex, final int toIndex) { - if (fromIndex == toIndex) return; - - final short[] buffer = this.buffer; - int i = toIndex; - do { - i = oneLeft(i, buffer.length); - if (!predicate.apply(buffer[i])) { - break; - } - } while (i != fromIndex); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - final short[] buffer = this.buffer; - final int last = tail; - final int bufLen = buffer.length; - int removed = 0; - int from, to; - from = to = head; - try { - for (from = to = head; from != last; from = oneRight(from, bufLen)) { - if (predicate.apply(buffer[from])) { - buffer[from] = ((short) 0); - removed++; - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((short) 0); - } - - to = oneRight(to, bufLen); - } - } finally { - // Keep the deque in consistent state even if the predicate throws an exception. - for (; from != last; from = oneRight(from, bufLen)) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((short) 0); - } - - to = oneRight(to, bufLen); - } - tail = to; - } - - return removed; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(short e) { - int fromIndex = head; - int toIndex = tail; - - final short[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - if (((e) == (buffer[i]))) { - return true; - } - } - - return false; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1; - int fromIndex = head; - int toIndex = tail; - - final short[] buffer = this.buffer; - for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare order-aligned elements against another {@link ShortDeque}. */ - protected boolean equalElements(ShortArrayDeque other) { - int max = size(); - if (other.size() != max) { - return false; - } - - Iterator i1 = this.iterator(); - Iterator i2 = other.iterator(); - - while (i1.hasNext() && i2.hasNext()) { - if (!((i1.next().value) == (i2.next().value))) { - return false; - } - } - - return !i1.hasNext() && !i2.hasNext(); - } - - /** Create a new deque by pushing a variable number of arguments to the end of it. */ - public static ShortArrayDeque from(short... elements) { - final ShortArrayDeque coll = new ShortArrayDeque(elements.length); - coll.addLast(elements); - return coll; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortArrayList.java b/sources/main/java/com/carrotsearch/hppc/ShortArrayList.java deleted file mode 100644 index cae87388..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortArrayList.java +++ /dev/null @@ -1,579 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.ShortPredicate; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** An array-backed list of shorts. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") -public class ShortArrayList extends AbstractShortCollection - implements ShortIndexedContainer, Preallocable, Cloneable, Accountable { - /** An immutable empty buffer (array). */ - public static final short[] EMPTY_ARRAY = new short[0]; - - ; - - /** Reuse the same strategy instance. */ - private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = - BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; - - /** - * Internal array for storing the list. The array may be larger than the current size ({@link - * #size()}). - */ - public short[] buffer = EMPTY_ARRAY; - - /** Current number of elements stored in {@link #buffer}. */ - public int elementsCount; - - /** Buffer resizing strategy. */ - protected final ArraySizingStrategy resizer; - - /** New instance with sane defaults. */ - public ShortArrayList() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortArrayList(int expectedElements) { - this(expectedElements, DEFAULT_SIZING_STRATEGY); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public ShortArrayList(int expectedElements, ArraySizingStrategy resizer) { - assert resizer != null; - this.resizer = resizer; - buffer = Arrays.copyOf(buffer, expectedElements); - } - - /** Creates a new list from the elements of another container in its iteration order. */ - public ShortArrayList(ShortContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public void add(short e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** - * Appends two elements at the end of the list. To add more than two elements, use add - * (vararg-version) or access the buffer directly (tight loop). - */ - public void add(short e1, short e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Add all elements from a range of given array to the list. */ - public void add(short[] elements, int start, int length) { - assert length >= 0 : "Length must be >= 0"; - - ensureBufferSpace(length); - System.arraycopy(elements, start, buffer, elementsCount, length); - elementsCount += length; - } - - /** - * Vararg-signature method for adding elements at the end of the list. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void add(short... elements) { - add(elements, 0, elements.length); - } - - /** Adds all elements from another container. */ - public int addAll(ShortContainer container) { - final int size = container.size(); - ensureBufferSpace(size); - - for (ShortCursor cursor : container) { - add(cursor.value); - } - - return size; - } - - /** Adds all elements from another iterable. */ - public int addAll(Iterable iterable) { - int size = 0; - for (ShortCursor cursor : iterable) { - add(cursor.value); - size++; - } - return size; - } - - /** {@inheritDoc} */ - @Override - public void insert(int index, short e1) { - assert (index >= 0 && index <= size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; - - ensureBufferSpace(1); - System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); - buffer[index] = e1; - elementsCount++; - } - - /** {@inheritDoc} */ - @Override - public short get(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - return buffer[index]; - } - - /** {@inheritDoc} */ - @Override - public short set(int index, short e1) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final short v = buffer[index]; - buffer[index] = e1; - return v; - } - - /** {@inheritDoc} */ - @Override - public short removeAt(int index) { - assert (index >= 0 && index < size()) - : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; - - final short v = buffer[index]; - System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); - - return v; - } - - /** {@inheritDoc} */ - @Override - public short removeLast() { - assert elementsCount > 0; - - final short v = buffer[--elementsCount]; - - return v; - } - - /** {@inheritDoc} */ - @Override - public void removeRange(int fromIndex, int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); - final int count = toIndex - fromIndex; - elementsCount -= count; - } - - /** {@inheritDoc} */ - @Override - public boolean removeElement(short e1) { - return removeFirst(e1) != -1; - } - - /** {@inheritDoc} */ - @Override - public int removeFirst(short e1) { - final int index = indexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeLast(short e1) { - final int index = lastIndexOf(e1); - if (index >= 0) removeAt(index); - return index; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(short e1) { - int to = 0; - for (int from = 0; from < elementsCount; from++) { - if (((e1) == (buffer[from]))) { - continue; - } - if (to != from) { - buffer[to] = buffer[from]; - } - to++; - } - final int deleted = elementsCount - to; - this.elementsCount = to; - - return deleted; - } - - /** {@inheritDoc} */ - @Override - public boolean contains(short e1) { - return indexOf(e1) >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexOf(short e1) { - for (int i = 0; i < elementsCount; i++) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public int lastIndexOf(short e1) { - for (int i = elementsCount - 1; i >= 0; i--) { - if (((e1) == (buffer[i]))) { - return i; - } - } - - return -1; - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return elementsCount == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (expectedElements > bufferLen) { - ensureBufferSpace(expectedElements - size()); - } - } - - /** - * Ensures the internal buffer has enough free slots to store expectedAdditions. - * Increases internal buffer size if needed. - */ - protected void ensureBufferSpace(int expectedAdditions) { - final int bufferLen = (buffer == null ? 0 : buffer.length); - if (elementsCount + expectedAdditions > bufferLen) { - final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); - assert newSize >= elementsCount + expectedAdditions - : "Resizer failed to" - + " return sensible new size: " - + newSize - + " <= " - + (elementsCount + expectedAdditions); - - this.buffer = Arrays.copyOf(buffer, newSize); - } - } - - /** - * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be - * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated - * values will be reset to the default value (zero). If the list is expanded, the elements beyond - * the current size are initialized with JVM-defaults (zero or null values). - */ - public void resize(int newSize) { - if (newSize <= buffer.length) { - if (newSize < elementsCount) { - Arrays.fill(buffer, newSize, elementsCount, ((short) 0)); - } else { - Arrays.fill(buffer, elementsCount, newSize, ((short) 0)); - } - } else { - ensureCapacity(newSize); - } - this.elementsCount = newSize; - } - - /** {@inheritDoc} */ - @Override - public int size() { - return elementsCount; - } - - /** Trim the internal buffer to the current size. */ - public void trimToSize() { - if (size() != this.buffer.length) { - this.buffer = toArray(); - } - } - - /** - * Sets the number of stored elements to zero. Releases and initializes the internal storage array - * to default values. To clear the list without cleaning the buffer, simply set the {@link - * #elementsCount} field to zero. - */ - @Override - public void clear() { - Arrays.fill(buffer, 0, elementsCount, ((short) 0)); - this.elementsCount = 0; - } - - /** Sets the number of stored elements to zero and releases the internal storage array. */ - @Override - public void release() { - this.buffer = EMPTY_ARRAY; - this.elementsCount = 0; - } - - /** - * {@inheritDoc} - * - *

The returned array is sized to match exactly the number of elements of the stack. - */ - @Override - public short[] toArray() { - - return Arrays.copyOf(buffer, elementsCount); - } - - /** {@inheritDoc} */ - @Override - public ShortIndexedContainer sort() { - Arrays.sort(buffer, 0, elementsCount); - return this; - } - - /** {@inheritDoc} */ - @Override - public ShortIndexedContainer reverse() { - for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { - short tmp = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = tmp; - } - return this; - } - - /** - * Clone this object. The returned clone will reuse the same hash function and array resizing - * strategy. - */ - @Override - public ShortArrayList clone() { - try { - - final ShortArrayList cloned = (ShortArrayList) super.clone(); - cloned.buffer = buffer.clone(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = 1, max = elementsCount; - for (int i = 0; i < max; i++) { - h = 31 * h + BitMixer.mix(this.buffer[i]); - } - return h; - } - - /** - * Returns true only if the other object is an instance of the same class and with - * the same elements. - */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Compare index-aligned elements against another {@link ShortIndexedContainer}. */ - protected boolean equalElements(ShortArrayList other) { - int max = size(); - if (other.size() != max) { - return false; - } - - for (int i = 0; i < max; i++) { - if (!((get(i)) == (other.get(i)))) { - return false; - } - } - - return true; - } - - @Override - public long ramBytesAllocated() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesAllocated() - + RamUsageEstimator.shallowSizeOfArray(buffer); - } - - @Override - public long ramBytesUsed() { - // int: elementsCount - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + Integer.BYTES - + resizer.ramBytesUsed() - + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); - } - - /** An iterator implementation for {@link ShortArrayList#iterator}. */ - static final class ValueIterator extends AbstractIterator { - private final ShortCursor cursor; - - private final short[] buffer; - private final int size; - - public ValueIterator(short[] buffer, int size) { - this.cursor = new ShortCursor(); - this.cursor.index = -1; - this.size = size; - this.buffer = buffer; - } - - @Override - protected ShortCursor fetch() { - if (cursor.index + 1 == size) return done(); - - cursor.value = buffer[++cursor.index]; - return cursor; - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new ValueIterator(buffer, size()); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - return forEach(procedure, 0, size()); - } - - /** - * Applies procedure to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive. - */ - public T forEach(T procedure, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final short[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - procedure.apply(buffer[i]); - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - final short[] buffer = this.buffer; - final int elementsCount = this.elementsCount; - int to = 0; - int from = 0; - try { - for (; from < elementsCount; from++) { - if (predicate.apply(buffer[from])) { - buffer[from] = ((short) 0); - continue; - } - - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((short) 0); - } - to++; - } - } finally { - // Keep the list in a consistent state, even if the predicate throws an exception. - for (; from < elementsCount; from++) { - if (to != from) { - buffer[to] = buffer[from]; - buffer[from] = ((short) 0); - } - to++; - } - - this.elementsCount = to; - } - - return elementsCount - to; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - return forEach(predicate, 0, size()); - } - - /** - * Applies predicate to a slice of the list, fromIndex, inclusive, to - * toIndex, exclusive, or until predicate returns false. - */ - public T forEach(T predicate, int fromIndex, final int toIndex) { - assert (fromIndex >= 0 && fromIndex <= size()) - : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; - assert (toIndex >= 0 && toIndex <= size()) - : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; - assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; - - final short[] buffer = this.buffer; - for (int i = fromIndex; i < toIndex; i++) { - if (!predicate.apply(buffer[i])) break; - } - - return predicate; - } - - /** - * Create a list from a variable number of arguments or an array of short. The - * elements are copied from the argument to the internal buffer. - */ - public static ShortArrayList from(short... elements) { - final ShortArrayList list = new ShortArrayList(elements.length); - list.add(elements); - return list; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortBufferVisualizer.java b/sources/main/java/com/carrotsearch/hppc/ShortBufferVisualizer.java deleted file mode 100644 index ce873652..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortBufferVisualizer.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Reused buffer visualization routines. - * - * @see ShortSet#visualizeKeyDistribution(int) - * @see ShortVTypeMap#visualizeKeyDistribution(int) - */ -class ShortBufferVisualizer { - static String visualizeKeyDistribution(short[] buffer, int max, int characters) { - final StringBuilder b = new StringBuilder(); - final char[] chars = ".123456789X".toCharArray(); - for (int i = 1, start = -1; i <= characters; i++) { - int end = (int) ((long) i * max / characters); - - if (start + 1 <= end) { - int taken = 0; - int slots = 0; - for (int slot = start + 1; slot <= end; slot++, slots++) { - if (!((buffer[slot]) == 0)) { - taken++; - } - } - b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); - start = end; - } - } - while (b.length() < characters) { - b.append(' '); - } - return b.toString(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortByteAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortByteAssociativeContainer.java deleted file mode 100644 index 27f4953d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortByteAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ShortContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ShortByteAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(short key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortBytePredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortByteProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortBytePredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ShortCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ByteContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortByteHashMap.java b/sources/main/java/com/carrotsearch/hppc/ShortByteHashMap.java deleted file mode 100644 index 049da077..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortByteHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of short to byte, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ShortByteHashMap implements ShortByteMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public short[] keys; - - /** The array holding values. */ - public byte[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ShortByteHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortByteHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ShortByteHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ShortByteHashMap(ShortByteAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public byte put(short key, byte value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - byte previousValue = hasEmptyKey ? values[mask + 1] : ((byte) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final byte previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ShortByteAssociativeContainer container) { - final int count = size(); - for (ShortByteCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (ShortByteCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public byte putOrAdd(short key, byte putValue, byte incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((byte) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public byte addTo(short key, byte incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public byte remove(short key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((byte) 0); - } - hasEmptyKey = false; - byte previousValue = values[mask + 1]; - values[mask + 1] = ((byte) 0); - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final byte previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ShortLookupContainer) { - if (hasEmptyKey && other.contains(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ShortCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortBytePredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((short) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - } - - final short[] keys = this.keys; - final byte[] values = this.values; - for (int slot = 0; slot <= mask; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((byte) 0); - } - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public byte get(short key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((byte) 0); - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((byte) 0); - } - } - - /** {@inheritDoc} */ - @Override - public byte getOrDefault(short key, byte defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(short key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(short key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public byte indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public byte indexReplace(int index, byte newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - byte previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, short key, byte value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public byte indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - byte previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((byte) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((short) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ShortByteCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(ShortByteHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ShortByteCursor c : other) { - short key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final short[] prevKeys = this.keys; - final byte[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortByteCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ShortByteCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortByteCursor fetch() { - final int mask = ShortByteHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((short) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final short[] keys = this.keys; - final byte[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((short) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final short[] keys = this.keys; - final byte[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((short) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { - private final ShortByteHashMap owner = ShortByteHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortByteProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortBytePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final short e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ShortByteHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((short) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ByteCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractByteCollection { - private final ShortByteHashMap owner = ShortByteHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(byte value) { - for (ShortByteCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ShortByteCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ShortByteCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final byte e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final BytePredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ByteCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ByteCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ByteCursor fetch() { - final int mask = ShortByteHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ShortByteHashMap clone() { - try { - - ShortByteHashMap cloned = (ShortByteHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ShortByteCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ShortByteHashMap from(short[] keys, byte[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ShortByteHashMap map = new ShortByteHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(short key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(short[] fromKeys, byte[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final short[] keys = this.keys; - final byte[] values = this.values; - final int mask = this.mask; - short existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - short[] prevKeys = this.keys; - byte[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new short[arraySize + emptyElementSlot]); - this.values = (new byte[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, short pendingKey, byte pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final short[] prevKeys = this.keys; - final byte[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final short[] keys = this.keys; - final byte[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final short existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((short) 0); - values[gapSlot] = ((byte) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortByteMap.java b/sources/main/java/com/carrotsearch/hppc/ShortByteMap.java deleted file mode 100644 index dfe9a67a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortByteMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortByteCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ShortByteMap extends ShortByteAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public byte get(short key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public byte getOrDefault(short key, byte defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public byte put(short key, byte value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(short key, byte value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ShortByteAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public byte putOrAdd(short key, byte putValue, byte incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public byte addTo(short key, byte additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public byte remove(short key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ShortByteMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(short key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexReplace(int index, byte newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, short key, byte value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public byte indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortCharAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortCharAssociativeContainer.java deleted file mode 100644 index 3ab6c85d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortCharAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ShortContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ShortCharAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(short key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortCharPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortCharProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortCharPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ShortCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public CharContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortCharHashMap.java b/sources/main/java/com/carrotsearch/hppc/ShortCharHashMap.java deleted file mode 100644 index cb29c12e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortCharHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of short to char, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ShortCharHashMap implements ShortCharMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public short[] keys; - - /** The array holding values. */ - public char[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ShortCharHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortCharHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ShortCharHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ShortCharHashMap(ShortCharAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public char put(short key, char value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - char previousValue = hasEmptyKey ? values[mask + 1] : ((char) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final char previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ShortCharAssociativeContainer container) { - final int count = size(); - for (ShortCharCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (ShortCharCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public char putOrAdd(short key, char putValue, char incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((char) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public char addTo(short key, char incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public char remove(short key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((char) 0); - } - hasEmptyKey = false; - char previousValue = values[mask + 1]; - values[mask + 1] = ((char) 0); - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final char previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ShortLookupContainer) { - if (hasEmptyKey && other.contains(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ShortCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortCharPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((short) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - } - - final short[] keys = this.keys; - final char[] values = this.values; - for (int slot = 0; slot <= mask; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((char) 0); - } - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public char get(short key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((char) 0); - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((char) 0); - } - } - - /** {@inheritDoc} */ - @Override - public char getOrDefault(short key, char defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(short key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(short key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public char indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public char indexReplace(int index, char newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - char previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, short key, char value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public char indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - char previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((char) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((short) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ShortCharCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(ShortCharHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ShortCharCursor c : other) { - short key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final short[] prevKeys = this.keys; - final char[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortCharCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ShortCharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCharCursor fetch() { - final int mask = ShortCharHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((short) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final short[] keys = this.keys; - final char[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((short) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final short[] keys = this.keys; - final char[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((short) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { - private final ShortCharHashMap owner = ShortCharHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortCharProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortCharPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final short e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ShortCharHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((short) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public CharCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractCharCollection { - private final ShortCharHashMap owner = ShortCharHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(char value) { - for (ShortCharCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ShortCharCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ShortCharCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final char e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final CharPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final CharCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new CharCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected CharCursor fetch() { - final int mask = ShortCharHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ShortCharHashMap clone() { - try { - - ShortCharHashMap cloned = (ShortCharHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ShortCharCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ShortCharHashMap from(short[] keys, char[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ShortCharHashMap map = new ShortCharHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(short key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(short[] fromKeys, char[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final short[] keys = this.keys; - final char[] values = this.values; - final int mask = this.mask; - short existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - short[] prevKeys = this.keys; - char[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new short[arraySize + emptyElementSlot]); - this.values = (new char[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, short pendingKey, char pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final short[] prevKeys = this.keys; - final char[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final short[] keys = this.keys; - final char[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final short existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((short) 0); - values[gapSlot] = ((char) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortCharMap.java b/sources/main/java/com/carrotsearch/hppc/ShortCharMap.java deleted file mode 100644 index 17bd928b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortCharMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortCharCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ShortCharMap extends ShortCharAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public char get(short key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public char getOrDefault(short key, char defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public char put(short key, char value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(short key, char value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ShortCharAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public char putOrAdd(short key, char putValue, char incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public char addTo(short key, char additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public char remove(short key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ShortCharMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(short key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexReplace(int index, char newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, short key, char value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public char indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortCollection.java b/sources/main/java/com/carrotsearch/hppc/ShortCollection.java deleted file mode 100644 index 372dfca5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortCollection.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.predicates.ShortPredicate; - -/** - * A collection allows basic, efficient operations on sets of elements (difference and - * intersection). - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") -public interface ShortCollection extends ShortContainer { - /** - * Removes all occurrences of e from this collection. - * - * @param e Element to be removed from this collection, if present. - * @return The number of removed elements as a result of this call. - */ - public int removeAll(short e); - - /** - * Removes all elements in this collection that are present in c. - * - * @return Returns the number of removed elements. - */ - public int removeAll(ShortLookupContainer c); - - /** - * Removes all elements in this collection for which the given predicate returns true - * . - * - * @return Returns the number of removed elements. - */ - public int removeAll(ShortPredicate predicate); - - /** - * Keeps all elements in this collection that are present in c. Runs in time - * proportional to the number of elements in this collection. Equivalent of sets intersection. - * - * @return Returns the number of removed elements. - */ - public int retainAll(ShortLookupContainer c); - - /** - * Keeps all elements in this collection for which the given predicate returns true. - * - * @return Returns the number of removed elements. - */ - public int retainAll(ShortPredicate predicate); - - /** - * Removes all elements from this collection. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortContainer.java deleted file mode 100644 index f425a1fe..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortContainer.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortCursor; -import com.carrotsearch.hppc.predicates.ShortPredicate; -import com.carrotsearch.hppc.procedures.ShortProcedure; -import java.util.Iterator; - -/** A generic container holding shorts. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") -public interface ShortContainer extends Iterable { - /** - * Returns an iterator to a cursor traversing the collection. The order of traversal is not - * defined. More than one cursor may be active at a time. The behavior of iterators is undefined - * if structural changes are made to the underlying collection. - * - *

The iterator is implemented as a cursor and it returns the same cursor instance on - * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current - * list's value (or index in the list) use the cursor's public fields. An example is shown below. - * - *

-   * for (ShortCursor<short> c : container) {
-   *   System.out.println("index=" + c.index + " value=" + c.value);
-   * }
-   * 
- */ - public Iterator iterator(); - - /** - * Lookup a given element in the container. This operation has no speed guarantees (may be linear - * with respect to the size of this container). - * - * @return Returns true if this container has an element equal to e. - */ - public boolean contains(short e); - - /** - * Return the current number of elements in this container. The time for calculating the - * container's size may take O(n) time, although implementing classes should try to - * maintain the current size and return in constant time. - */ - public int size(); - - /** Shortcut for size() == 0. */ - public boolean isEmpty(); - - /** - * Copies all elements of this container to an array. - * - *

The returned array is always a copy, regardless of the storage used by the container. - */ - public short[] toArray(); - - /** - * Applies a procedure to all container elements. Returns the argument (any subclass - * of {@link ShortProcedure}. This lets the caller to call methods of the argument by chaining the - * call (even if the argument is an anonymous type) to retrieve computed values, for example - * (IntContainer): - * - *

-   * int count = container.forEach(new IntProcedure() {
-   *   int count; // this is a field declaration in an anonymous class.
-   *
-   *   public void apply(int value) {
-   *     count++;
-   *   }
-   * }).count;
-   * 
- */ - public T forEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T forEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortDeque.java b/sources/main/java/com/carrotsearch/hppc/ShortDeque.java deleted file mode 100644 index 244b6a6a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortDeque.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortCursor; -import com.carrotsearch.hppc.predicates.ShortPredicate; -import com.carrotsearch.hppc.procedures.ShortProcedure; -import java.util.Deque; -import java.util.Iterator; - -/** - * A linear collection that supports element insertion and removal at both ends. - * - * @see Deque - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") -public interface ShortDeque extends ShortCollection { - /** - * Removes the first element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeFirst(short e); - - /** - * Removes the last element that equals e. - * - * @return The deleted element's index or -1 if the element was not found. - */ - public int removeLast(short e); - - /** Inserts the specified element at the front of this deque. */ - public void addFirst(short e); - - /** Inserts the specified element at the end of this deque. */ - public void addLast(short e); - - /** - * Retrieves and removes the first element of this deque. - * - * @return the head (first) element of this deque. - */ - public short removeFirst(); - - /** - * Retrieves and removes the last element of this deque. - * - * @return the tail of this deque. - */ - public short removeLast(); - - /** - * Retrieves the first element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public short getFirst(); - - /** - * Retrieves the last element of this deque but does not remove it. - * - * @return the head of this deque. - */ - public short getLast(); - - /** - * @return An iterator over elements in this deque in tail-to-head order. - */ - public Iterator descendingIterator(); - - /** Applies a procedure to all elements in tail-to-head order. */ - public T descendingForEach(T procedure); - - /** - * Applies a predicate to container elements as long, as the predicate returns - * true. The iteration is interrupted otherwise. - */ - public T descendingForEach(T predicate); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortDoubleAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortDoubleAssociativeContainer.java deleted file mode 100644 index 0155b8a3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortDoubleAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ShortContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ShortDoubleAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *
-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(short key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortDoublePredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortDoubleProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortDoublePredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ShortCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public DoubleContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortDoubleHashMap.java b/sources/main/java/com/carrotsearch/hppc/ShortDoubleHashMap.java deleted file mode 100644 index 4bf50582..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortDoubleHashMap.java +++ /dev/null @@ -1,1082 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of short to double, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ShortDoubleHashMap implements ShortDoubleMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public short[] keys; - - /** The array holding values. */ - public double[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ShortDoubleHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortDoubleHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ShortDoubleHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ShortDoubleHashMap(ShortDoubleAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public double put(short key, double value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - double previousValue = hasEmptyKey ? values[mask + 1] : 0d; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final double previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ShortDoubleAssociativeContainer container) { - final int count = size(); - for (ShortDoubleCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (ShortDoubleCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public double putOrAdd(short key, double putValue, double incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((double) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public double addTo(short key, double incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public double remove(short key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0d; - } - hasEmptyKey = false; - double previousValue = values[mask + 1]; - values[mask + 1] = 0d; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final double previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ShortLookupContainer) { - if (hasEmptyKey && other.contains(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ShortCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortDoublePredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((short) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - } - - final short[] keys = this.keys; - final double[] values = this.values; - for (int slot = 0; slot <= mask; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0d; - } - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public double get(short key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0d; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0d; - } - } - - /** {@inheritDoc} */ - @Override - public double getOrDefault(short key, double defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(short key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(short key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public double indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public double indexReplace(int index, double newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - double previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, short key, double value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public double indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - double previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0d; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((short) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ShortDoubleCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(ShortDoubleHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ShortDoubleCursor c : other) { - short key = c.key; - if (!containsKey(key) - || !(Double.doubleToLongBits(c.value) == Double.doubleToLongBits(get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final short[] prevKeys = this.keys; - final double[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortDoubleCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ShortDoubleCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortDoubleCursor fetch() { - final int mask = ShortDoubleHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((short) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final short[] keys = this.keys; - final double[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((short) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final short[] keys = this.keys; - final double[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((short) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { - private final ShortDoubleHashMap owner = ShortDoubleHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortDoubleProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortDoublePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final short e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ShortDoubleHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((short) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public DoubleCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractDoubleCollection { - private final ShortDoubleHashMap owner = ShortDoubleHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(double value) { - for (ShortDoubleCursor c : owner) { - if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ShortDoubleCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ShortDoubleCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final double e) { - return owner.removeAll( - (key, value) -> (Double.doubleToLongBits(e) == Double.doubleToLongBits(value))); - } - - @Override - public int removeAll(final DoublePredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final DoubleCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new DoubleCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected DoubleCursor fetch() { - final int mask = ShortDoubleHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ShortDoubleHashMap clone() { - try { - - ShortDoubleHashMap cloned = (ShortDoubleHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ShortDoubleCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ShortDoubleHashMap from(short[] keys, double[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ShortDoubleHashMap map = new ShortDoubleHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(short key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(short[] fromKeys, double[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final short[] keys = this.keys; - final double[] values = this.values; - final int mask = this.mask; - short existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - short[] prevKeys = this.keys; - double[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new short[arraySize + emptyElementSlot]); - this.values = (new double[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, short pendingKey, double pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final short[] prevKeys = this.keys; - final double[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final short[] keys = this.keys; - final double[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final short existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((short) 0); - values[gapSlot] = 0d; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortDoubleMap.java b/sources/main/java/com/carrotsearch/hppc/ShortDoubleMap.java deleted file mode 100644 index 8d3ac5f8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortDoubleMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortDoubleCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ShortDoubleMap extends ShortDoubleAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public double get(short key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public double getOrDefault(short key, double defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public double put(short key, double value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(short key, double value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ShortDoubleAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public double putOrAdd(short key, double putValue, double incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public double addTo(short key, double additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public double remove(short key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ShortDoubleMap} and both objects contains exactly the - * same key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(short key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexReplace(int index, double newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, short key, double value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public double indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortFloatAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortFloatAssociativeContainer.java deleted file mode 100644 index f6a2bf72..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortFloatAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ShortContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ShortFloatAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(short key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortFloatPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortFloatProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortFloatPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ShortCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public FloatContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortFloatHashMap.java b/sources/main/java/com/carrotsearch/hppc/ShortFloatHashMap.java deleted file mode 100644 index 9383ebab..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortFloatHashMap.java +++ /dev/null @@ -1,1081 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of short to float, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ShortFloatHashMap implements ShortFloatMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public short[] keys; - - /** The array holding values. */ - public float[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ShortFloatHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortFloatHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ShortFloatHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ShortFloatHashMap(ShortFloatAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public float put(short key, float value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - float previousValue = hasEmptyKey ? values[mask + 1] : 0f; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final float previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ShortFloatAssociativeContainer container) { - final int count = size(); - for (ShortFloatCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (ShortFloatCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public float putOrAdd(short key, float putValue, float incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((float) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public float addTo(short key, float incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public float remove(short key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0f; - } - hasEmptyKey = false; - float previousValue = values[mask + 1]; - values[mask + 1] = 0f; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final float previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ShortLookupContainer) { - if (hasEmptyKey && other.contains(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ShortCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortFloatPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((short) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - } - - final short[] keys = this.keys; - final float[] values = this.values; - for (int slot = 0; slot <= mask; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0f; - } - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public float get(short key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0f; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0f; - } - } - - /** {@inheritDoc} */ - @Override - public float getOrDefault(short key, float defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(short key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(short key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public float indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public float indexReplace(int index, float newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - float previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, short key, float value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public float indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - float previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0f; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((short) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ShortFloatCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(ShortFloatHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ShortFloatCursor c : other) { - short key = c.key; - if (!containsKey(key) || !(Float.floatToIntBits(c.value) == Float.floatToIntBits(get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final short[] prevKeys = this.keys; - final float[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortFloatCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ShortFloatCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortFloatCursor fetch() { - final int mask = ShortFloatHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((short) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final short[] keys = this.keys; - final float[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((short) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final short[] keys = this.keys; - final float[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((short) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { - private final ShortFloatHashMap owner = ShortFloatHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortFloatProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortFloatPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final short e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ShortFloatHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((short) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public FloatCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractFloatCollection { - private final ShortFloatHashMap owner = ShortFloatHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(float value) { - for (ShortFloatCursor c : owner) { - if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ShortFloatCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ShortFloatCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final float e) { - return owner.removeAll( - (key, value) -> (Float.floatToIntBits(e) == Float.floatToIntBits(value))); - } - - @Override - public int removeAll(final FloatPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final FloatCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new FloatCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected FloatCursor fetch() { - final int mask = ShortFloatHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ShortFloatHashMap clone() { - try { - - ShortFloatHashMap cloned = (ShortFloatHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ShortFloatCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ShortFloatHashMap from(short[] keys, float[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ShortFloatHashMap map = new ShortFloatHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(short key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(short[] fromKeys, float[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final short[] keys = this.keys; - final float[] values = this.values; - final int mask = this.mask; - short existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - short[] prevKeys = this.keys; - float[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new short[arraySize + emptyElementSlot]); - this.values = (new float[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, short pendingKey, float pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final short[] prevKeys = this.keys; - final float[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final short[] keys = this.keys; - final float[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final short existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((short) 0); - values[gapSlot] = 0f; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortFloatMap.java b/sources/main/java/com/carrotsearch/hppc/ShortFloatMap.java deleted file mode 100644 index d09dac18..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortFloatMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortFloatCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ShortFloatMap extends ShortFloatAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public float get(short key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public float getOrDefault(short key, float defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public float put(short key, float value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(short key, float value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ShortFloatAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public float putOrAdd(short key, float putValue, float incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public float addTo(short key, float additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public float remove(short key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ShortFloatMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(short key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexReplace(int index, float newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, short key, float value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public float indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortHashSet.java b/sources/main/java/com/carrotsearch/hppc/ShortHashSet.java deleted file mode 100644 index f2f35006..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortHashSet.java +++ /dev/null @@ -1,787 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash set of shorts, implemented using open addressing with linear probing for - * collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java") -public class ShortHashSet extends AbstractShortCollection - implements ShortLookupContainer, ShortSet, Preallocable, Cloneable, Accountable { - /** The hash array holding keys. */ - public short[] keys; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any. - * - * @see #size() - * @see #hasEmptyKey - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** - * New instance with sane defaults. - * - * @see #ShortHashSet(int, double) - */ - public ShortHashSet() { - this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with sane defaults. - * - * @see #ShortHashSet(int, double) - */ - public ShortHashSet(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ShortHashSet(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** New instance copying elements from another {@link ShortContainer}. */ - public ShortHashSet(ShortContainer container) { - this(container.size()); - addAll(container); - } - - /** {@inheritDoc} */ - @Override - public boolean add(short key) { - if (((key) == 0)) { - assert ((keys[mask + 1]) == 0); - boolean added = !hasEmptyKey; - hasEmptyKey = true; - return added; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return false; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key); - } else { - keys[slot] = key; - } - - assigned++; - return true; - } - } - - /** - * Adds all elements from the given list (vararg) to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public final int addAll(short... elements) { - ensureCapacity(elements.length); - int count = 0; - for (short e : elements) { - if (add(e)) { - count++; - } - } - return count; - } - - /** - * Adds all elements from the given {@link ShortContainer} to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public int addAll(ShortContainer container) { - ensureCapacity(container.size()); - return addAll((Iterable) container); - } - - /** - * Adds all elements from the given iterable to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - */ - public int addAll(Iterable iterable) { - int count = 0; - for (ShortCursor cursor : iterable) { - if (add(cursor.value)) { - count++; - } - } - return count; - } - - /** {@inheritDoc} */ - @Override - public short[] toArray() { - - final short[] cloned = (new short[size()]); - int j = 0; - if (hasEmptyKey) { - cloned[j++] = ((short) 0); - } - - final short[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - short existing; - if (!((existing = keys[slot]) == 0)) { - cloned[j++] = existing; - } - } - - return cloned; - } - - /** An alias for the (preferred) {@link #removeAll}. */ - public boolean remove(short key) { - if (((key) == 0)) { - boolean hadEmptyKey = hasEmptyKey; - hasEmptyKey = false; - return hadEmptyKey; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - shiftConflictingKeys(slot); - return true; - } - slot = (slot + 1) & mask; - } - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(short key) { - return remove(key) ? 1 : 0; - } - - /** - * Removes all keys present in a given container. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortContainer other) { - final int before = size(); - - // Try to iterate over the smaller set or over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ShortLookupContainer) { - if (hasEmptyKey && other.contains(((short) 0))) { - hasEmptyKey = false; - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ShortCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((short) 0))) { - hasEmptyKey = false; - } - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0)) { - if (predicate.apply(existing)) { - shiftConflictingKeys(slot); - continue; // Repeat the check for the same slot i (shifted). - } - } - slot++; - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public boolean contains(short key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - return false; - } - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - Arrays.fill(keys, ((short) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - keys = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return size() == 0; - } - - /** - * Ensure this container can hold at least the given number of elements without resizing its - * buffers. - * - * @param expectedElements The total number of elements, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final short[] prevKeys = this.keys; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys); - } - } - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - final short[] keys = this.keys; - for (int slot = mask; slot >= 0; slot--) { - short existing; - if (!((existing = keys[slot]) == 0)) { - h += BitMixer.mix(existing); - } - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - private boolean sameKeys(ShortSet other) { - if (other.size() != size()) { - return false; - } - - for (ShortCursor c : other) { - if (!contains(c.value)) { - return false; - } - } - - return true; - } - - /** {@inheritDoc} */ - @Override - public ShortHashSet clone() { - try { - - ShortHashSet cloned = (ShortHashSet) super.clone(); - cloned.keys = keys.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - @Override - public long ramBytesAllocated() { - // int: assigned, mask, keyMixer, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys); - } - - @Override - public long ramBytesUsed() { - // int: assigned, mask, keyMixer, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - protected final class EntryIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ShortHashSet.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((short) 0); - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - if (hasEmptyKey) { - procedure.apply(((short) 0)); - } - - final short[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - short existing; - if (!((existing = keys[slot]) == 0)) { - procedure.apply(existing); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - if (hasEmptyKey) { - if (!predicate.apply(((short) 0))) { - return predicate; - } - } - - final short[] keys = this.keys; - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - short existing; - if (!((existing = keys[slot]) == 0)) { - if (!predicate.apply(existing)) { - break; - } - } - } - - return predicate; - } - - /** - * Create a set from a variable number of arguments or an array of short. The - * elements are copied from the argument to the internal buffer. - */ - public static ShortHashSet from(short... elements) { - final ShortHashSet set = new ShortHashSet(elements.length); - set.addAll(elements); - return set; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(short key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up logic in - * certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between modifications (it will not be affected by read-only - * operations). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the set. - * @return A non-negative value of the logical "index" of the key in the set or a negative value - * if the key did not exist. - */ - public int indexOf(short key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index) { - assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** - * Returns the exact value of the existing key. This method makes sense for sets of objects which - * define custom key-equality relationship. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the equivalent key currently stored in the set. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return keys[index]; - } - - /** - * Replaces the existing equivalent key with the given one and returns any previous value stored - * for that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key - * currently stored at the provided index. - * @return Returns the previous key stored in the set. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexReplace(int index, short equivalentKey) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - assert ((keys[index]) == (equivalentKey)); - - short previousValue = keys[index]; - keys[index] = equivalentKey; - return previousValue; - } - - /** - * Inserts a key for an index that is not present in the set. This method may help in avoiding - * double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public void indexInsert(int index, short key) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - assert ((keys[index]) == 0); - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key); - } else { - keys[index] = key; - } - - assigned++; - } - } - - /** - * Removes a key at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public void indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - if (index > mask) { - hasEmptyKey = false; - } else { - shiftConflictingKeys(index); - } - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(short[] fromKeys) { - assert HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored keys into the new buffers. - final short[] keys = this.keys; - final int mask = this.mask; - short existing; - for (int i = fromKeys.length - 1; --i >= 0; ) { - if (!((existing = fromKeys[i]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - short[] prevKeys = this.keys; - try { - int emptyElementSlot = 1; - this.keys = (new short[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.keys == null ? 0 : size(), arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key to be inserted into the buffer but there is not - * enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, short pendingKey) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final short[] prevKeys = this.keys; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - - // Rehash old keys, including the pending key. - rehash(prevKeys); - } - - /** Shift all the slot-conflicting keys allocated to (and including) slot. */ - protected void shiftConflictingKeys(int gapSlot) { - final short[] keys = this.keys; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final short existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((short) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortIndexedContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortIndexedContainer.java deleted file mode 100644 index fc7a41cf..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortIndexedContainer.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.carrotsearch.hppc; - -import java.util.RandomAccess; - -/** - * An indexed container provides random access to elements based on an index. Indexes - * are zero-based. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeIndexedContainer.java") -public interface ShortIndexedContainer extends ShortCollection, RandomAccess { - /** - * Removes the first element that equals e1, returning whether an element has been - * removed. - */ - public boolean removeElement(short e1); - - /** - * Removes the first element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeFirst(short e1); - - /** - * Removes the last element that equals e1, returning its deleted position or - * -1 if the element was not found. - */ - public int removeLast(short e1); - - /** - * Returns the index of the first occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int indexOf(short e1); - - /** - * Returns the index of the last occurrence of the specified element in this list, or -1 if this - * list does not contain the element. - */ - public int lastIndexOf(short e1); - - /** Adds an element to the end of this container (the last index is incremented by one). */ - public void add(short e1); - - /** - * Inserts the specified element at the specified position in this list. - * - * @param index The index at which the element should be inserted, shifting any existing and - * subsequent elements to the right. - */ - public void insert(int index, short e1); - - /** - * Replaces the element at the specified position in this list with the specified element. - * - * @return Returns the previous value in the list. - */ - public short set(int index, short e1); - - /** - * @return Returns the element at index index from the list. - */ - public short get(int index); - - /** - * Removes the element at the specified position in this container and returns it. - * - * @see #removeFirst - * @see #removeLast - * @see #removeAll - */ - public short removeAt(int index); - - /** Removes and returns the last element of this container. This container must not be empty. */ - public short removeLast(); - - /** - * Removes from this container all of the elements with indexes between fromIndex, - * inclusive, and toIndex, exclusive. - */ - public void removeRange(int fromIndex, int toIndex); - - /** Returns this container elements as a stream. */ - - /** Sorts the elements in this container and returns this container. */ - public ShortIndexedContainer sort(); - - /** Reverses the elements in this container and returns this container. */ - public ShortIndexedContainer reverse(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortIntAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortIntAssociativeContainer.java deleted file mode 100644 index 07b4a19b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortIntAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ShortContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ShortIntAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(short key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortIntPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortIntProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortIntPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ShortCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public IntContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortIntHashMap.java b/sources/main/java/com/carrotsearch/hppc/ShortIntHashMap.java deleted file mode 100644 index 07bea9e2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortIntHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of short to int, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ShortIntHashMap implements ShortIntMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public short[] keys; - - /** The array holding values. */ - public int[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ShortIntHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortIntHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ShortIntHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ShortIntHashMap(ShortIntAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public int put(short key, int value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - int previousValue = hasEmptyKey ? values[mask + 1] : 0; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final int previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ShortIntAssociativeContainer container) { - final int count = size(); - for (ShortIntCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (ShortIntCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public int putOrAdd(short key, int putValue, int incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((int) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public int addTo(short key, int incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public int remove(short key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0; - } - hasEmptyKey = false; - int previousValue = values[mask + 1]; - values[mask + 1] = 0; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final int previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ShortLookupContainer) { - if (hasEmptyKey && other.contains(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ShortCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortIntPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((short) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - } - - final short[] keys = this.keys; - final int[] values = this.values; - for (int slot = 0; slot <= mask; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0; - } - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int get(short key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public int getOrDefault(short key, int defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(short key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(short key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public int indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public int indexReplace(int index, int newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - int previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, short key, int value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public int indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - int previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((short) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ShortIntCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(ShortIntHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ShortIntCursor c : other) { - short key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final short[] prevKeys = this.keys; - final int[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortIntCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ShortIntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortIntCursor fetch() { - final int mask = ShortIntHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((short) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final short[] keys = this.keys; - final int[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((short) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final short[] keys = this.keys; - final int[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((short) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { - private final ShortIntHashMap owner = ShortIntHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortIntProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortIntPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final short e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ShortIntHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((short) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public IntCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractIntCollection { - private final ShortIntHashMap owner = ShortIntHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(int value) { - for (ShortIntCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ShortIntCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ShortIntCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final int e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final IntPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final IntCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new IntCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected IntCursor fetch() { - final int mask = ShortIntHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ShortIntHashMap clone() { - try { - - ShortIntHashMap cloned = (ShortIntHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ShortIntCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ShortIntHashMap from(short[] keys, int[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ShortIntHashMap map = new ShortIntHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(short key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(short[] fromKeys, int[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final short[] keys = this.keys; - final int[] values = this.values; - final int mask = this.mask; - short existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - short[] prevKeys = this.keys; - int[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new short[arraySize + emptyElementSlot]); - this.values = (new int[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, short pendingKey, int pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final short[] prevKeys = this.keys; - final int[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final short[] keys = this.keys; - final int[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final short existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((short) 0); - values[gapSlot] = 0; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortIntMap.java b/sources/main/java/com/carrotsearch/hppc/ShortIntMap.java deleted file mode 100644 index 78f19f42..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortIntMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortIntCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ShortIntMap extends ShortIntAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public int get(short key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public int getOrDefault(short key, int defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public int put(short key, int value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(short key, int value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ShortIntAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public int putOrAdd(short key, int putValue, int incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public int addTo(short key, int additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public int remove(short key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ShortIntMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(short key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexReplace(int index, int newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, short key, int value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public int indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortLongAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortLongAssociativeContainer.java deleted file mode 100644 index 32375150..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortLongAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ShortContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ShortLongAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(short key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortLongPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortLongProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortLongPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ShortCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public LongContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortLongHashMap.java b/sources/main/java/com/carrotsearch/hppc/ShortLongHashMap.java deleted file mode 100644 index 2fe676e5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortLongHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of short to long, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ShortLongHashMap implements ShortLongMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public short[] keys; - - /** The array holding values. */ - public long[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ShortLongHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortLongHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ShortLongHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ShortLongHashMap(ShortLongAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public long put(short key, long value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - long previousValue = hasEmptyKey ? values[mask + 1] : 0L; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final long previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ShortLongAssociativeContainer container) { - final int count = size(); - for (ShortLongCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (ShortLongCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public long putOrAdd(short key, long putValue, long incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((long) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public long addTo(short key, long incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public long remove(short key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return 0L; - } - hasEmptyKey = false; - long previousValue = values[mask + 1]; - values[mask + 1] = 0L; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final long previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ShortLookupContainer) { - if (hasEmptyKey && other.contains(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ShortCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortLongPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((short) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - } - - final short[] keys = this.keys; - final long[] values = this.values; - for (int slot = 0; slot <= mask; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = 0L; - } - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public long get(short key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : 0L; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return 0L; - } - } - - /** {@inheritDoc} */ - @Override - public long getOrDefault(short key, long defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(short key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(short key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public long indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public long indexReplace(int index, long newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - long previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, short key, long value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public long indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - long previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = 0L; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((short) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ShortLongCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(ShortLongHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ShortLongCursor c : other) { - short key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final short[] prevKeys = this.keys; - final long[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortLongCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ShortLongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortLongCursor fetch() { - final int mask = ShortLongHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((short) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final short[] keys = this.keys; - final long[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((short) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final short[] keys = this.keys; - final long[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((short) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { - private final ShortLongHashMap owner = ShortLongHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortLongProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortLongPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final short e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ShortLongHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((short) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public LongCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractLongCollection { - private final ShortLongHashMap owner = ShortLongHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(long value) { - for (ShortLongCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ShortLongCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ShortLongCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final long e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final LongPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final LongCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new LongCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected LongCursor fetch() { - final int mask = ShortLongHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ShortLongHashMap clone() { - try { - - ShortLongHashMap cloned = (ShortLongHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ShortLongCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ShortLongHashMap from(short[] keys, long[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ShortLongHashMap map = new ShortLongHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(short key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(short[] fromKeys, long[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final short[] keys = this.keys; - final long[] values = this.values; - final int mask = this.mask; - short existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - short[] prevKeys = this.keys; - long[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new short[arraySize + emptyElementSlot]); - this.values = (new long[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, short pendingKey, long pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final short[] prevKeys = this.keys; - final long[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final short[] keys = this.keys; - final long[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final short existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((short) 0); - values[gapSlot] = 0L; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortLongMap.java b/sources/main/java/com/carrotsearch/hppc/ShortLongMap.java deleted file mode 100644 index 682a924f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortLongMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortLongCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ShortLongMap extends ShortLongAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public long get(short key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public long getOrDefault(short key, long defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public long put(short key, long value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(short key, long value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ShortLongAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public long putOrAdd(short key, long putValue, long incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public long addTo(short key, long additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public long remove(short key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ShortLongMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(short key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexReplace(int index, long newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, short key, long value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public long indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortLookupContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortLookupContainer.java deleted file mode 100644 index c049ef8f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortLookupContainer.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.carrotsearch.hppc; - -/** - * Marker interface for containers that can check if they contain a given object in at least time - * O(log n) and ideally in amortized constant time O(1). - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeLookupContainer.java") -public interface ShortLookupContainer extends ShortContainer { - public boolean contains(short e); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortObjectAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortObjectAssociativeContainer.java deleted file mode 100644 index 0c3b670b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortObjectAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ShortContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ShortObjectAssociativeContainer extends Iterable> { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator> iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(short key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortObjectPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortObjectProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public > T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortObjectPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public > T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ShortCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ObjectContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortObjectHashMap.java b/sources/main/java/com/carrotsearch/hppc/ShortObjectHashMap.java deleted file mode 100644 index 6b8a20b0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortObjectHashMap.java +++ /dev/null @@ -1,1050 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of short to Object, implemented using open addressing with - * linear probing for collision resolution. Supports null values. - * - * @see HPPC interfaces diagram - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ShortObjectHashMap - implements ShortObjectMap, Preallocable, Cloneable, Accountable { - /** The array holding keys. */ - public short[] keys; - - /** The array holding values. */ - public Object[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ShortObjectHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortObjectHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ShortObjectHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ShortObjectHashMap(ShortObjectAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public VType put(short key, VType value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - VType previousValue = hasEmptyKey ? (VType) values[mask + 1] : null; - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final VType previousValue = (VType) values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return null; - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ShortObjectAssociativeContainer container) { - final int count = size(); - for (ShortObjectCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable> iterable) { - final int count = size(); - for (ShortObjectCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** {@inheritDoc} */ - @Override - public VType remove(short key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return null; - } - hasEmptyKey = false; - VType previousValue = (VType) values[mask + 1]; - values[mask + 1] = null; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final VType previousValue = (VType) values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return null; - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ShortLookupContainer) { - if (hasEmptyKey && other.contains(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = null; - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ShortCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortObjectPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((short) 0), (VType) values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = null; - } - } - - final short[] keys = this.keys; - final VType[] values = (VType[]) this.values; - for (int slot = 0; slot <= mask; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = null; - } - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public VType get(short key) { - if (((key) == 0)) { - return hasEmptyKey ? (VType) values[mask + 1] : null; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return (VType) values[slot]; - } - slot = (slot + 1) & mask; - } - - return null; - } - } - - /** {@inheritDoc} */ - @Override - public VType getOrDefault(short key, VType defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? (VType) values[mask + 1] : defaultValue; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return (VType) values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(short key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(short key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public VType indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return (VType) values[index]; - } - - /** {@inheritDoc} */ - @Override - public VType indexReplace(int index, VType newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - VType previousValue = (VType) values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, short key, VType value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public VType indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - VType previousValue = (VType) values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = null; - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((short) 0)); - - Arrays.fill(values, null); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ShortObjectCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** - * Return true if all keys of some other container exist in this container. Values are compared - * using {@link Objects#equals(Object)} method. - */ - protected boolean equalElements(ShortObjectHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ShortObjectCursor c : other) { - short key = c.key; - if (!containsKey(key) || !java.util.Objects.equals(c.value, get(key))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final short[] prevKeys = this.keys; - final VType[] prevValues = (VType[]) this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ShortObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ShortObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortObjectCursor fetch() { - final int mask = ShortObjectHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = (VType) values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((short) 0); - cursor.value = (VType) values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator> iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T procedure) { - final short[] keys = this.keys; - final VType[] values = (VType[]) this.values; - - if (hasEmptyKey) { - procedure.apply(((short) 0), (VType) values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public > T forEach(T predicate) { - final short[] keys = this.keys; - final VType[] values = (VType[]) this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((short) 0), (VType) values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { - private final ShortObjectHashMap owner = ShortObjectHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortObjectProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortObjectPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final short e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ShortObjectHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((short) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ObjectCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractObjectCollection { - private final ShortObjectHashMap owner = ShortObjectHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(VType value) { - for (ShortObjectCursor c : owner) { - if (java.util.Objects.equals(value, c.value)) { - return true; - } - } - return false; - } - - @Override - public > T forEach(T procedure) { - for (ShortObjectCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - for (ShortObjectCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator> iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final VType e) { - return owner.removeAll((key, value) -> java.util.Objects.equals(e, value)); - } - - @Override - public int removeAll(final ObjectPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator> { - private final ObjectCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ObjectCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ObjectCursor fetch() { - final int mask = ShortObjectHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = (VType) values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = (VType) values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ShortObjectHashMap clone() { - try { - - ShortObjectHashMap cloned = (ShortObjectHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ShortObjectCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ShortObjectHashMap from(short[] keys, VType[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ShortObjectHashMap map = new ShortObjectHashMap<>(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(short key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(short[] fromKeys, VType[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final short[] keys = this.keys; - final VType[] values = (VType[]) this.values; - final int mask = this.mask; - short existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - short[] prevKeys = this.keys; - VType[] prevValues = (VType[]) this.values; - try { - int emptyElementSlot = 1; - this.keys = (new short[arraySize + emptyElementSlot]); - this.values = ((VType[]) new Object[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, short pendingKey, VType pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final short[] prevKeys = this.keys; - final VType[] prevValues = (VType[]) this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final short[] keys = this.keys; - final VType[] values = (VType[]) this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final short existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((short) 0); - values[gapSlot] = null; - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortObjectMap.java b/sources/main/java/com/carrotsearch/hppc/ShortObjectMap.java deleted file mode 100644 index 732c57e7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortObjectMap.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortObjectCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ShortObjectMap extends ShortObjectAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public VType get(short key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public VType getOrDefault(short key, VType defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public VType put(short key, VType value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(short key, VType value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ShortObjectAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable> iterable); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public VType remove(short key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ShortObjectMap} and both objects contains exactly the - * same key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(short key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexReplace(int index, VType newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, short key, VType value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public VType indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortSet.java b/sources/main/java/com/carrotsearch/hppc/ShortSet.java deleted file mode 100644 index f87250b4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortSet.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.carrotsearch.hppc; - -/** A set of shorts. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java") -public interface ShortSet extends ShortCollection { - /** - * Adds k to the set. - * - * @return Returns true if this element was not part of the set before. Returns - * false if an equal element is already part of the set, does not replace the - * existing element with the argument. - */ - public boolean add(short k); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); - - /** - * Adds all elements from the given {@link ShortContainer} to this set. - * - * @return Returns the number of elements actually added as a result of this call (not previously - * present in the set). - * @since 0.9.1 - */ - public int addAll(ShortContainer container); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortShortAssociativeContainer.java b/sources/main/java/com/carrotsearch/hppc/ShortShortAssociativeContainer.java deleted file mode 100644 index e1adb957..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortShortAssociativeContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.Iterator; - -/** - * An associative container from keys to (one or possibly more) values. - * - * @see ShortContainer - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeAssociativeContainer.java") -public interface ShortShortAssociativeContainer extends Iterable { - /** - * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as - * a cursor and it returns the same cursor instance on every call to {@link - * Iterator#next()}. To read the current key and value use the cursor's public fields. An example - * is shown below. - * - *

-   * for (IntShortCursor c : intShortMap) {
-   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
-   * }
- * - *

The index field inside the cursor gives the internal index inside the - * container's implementation. The interpretation of this index depends on to the container. - */ - @Override - public Iterator iterator(); - - /** - * Returns true if this container has an association to a value for the given key. - */ - public boolean containsKey(short key); - - /** - * @return Returns the current size (number of assigned keys) in the container. - */ - public int size(); - - /** - * @return Return true if this hash map contains no assigned keys. - */ - public boolean isEmpty(); - - /** - * Removes all keys (and associated values) present in a given container. An alias to: - * - *

-   * keys().removeAll(container)
-   * 
- * - * but with no additional overhead. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortContainer container); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortPredicate predicate); - - /** - * Removes all keys (and associated values) for which the predicate returns true. - * - * @return Returns the number of elements actually removed as a result of this call. - */ - public int removeAll(ShortShortPredicate predicate); - - /** - * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortShortProcedure}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - */ - public T forEach(T procedure); - - /** - * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any - * subclass of {@link ShortShortPredicate}. This lets the caller call methods of the argument by - * chaining the call (even if the argument is an anonymous type) to retrieve computed values. - * - *

The iteration is continued as long as the predicate returns true. - */ - public T forEach(T predicate); - - /** - * Returns a collection of keys of this container. The returned collection is a view over the key - * set and any modifications (if allowed) introduced to the collection will propagate to the - * associative container immediately. - */ - public ShortCollection keys(); - - /** - * Returns a container view of all values present in this container. The returned collection is a - * view over the key set and any modifications (if allowed) introduced to the collection will - * propagate to the associative container immediately. - */ - public ShortContainer values(); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortShortHashMap.java b/sources/main/java/com/carrotsearch/hppc/ShortShortHashMap.java deleted file mode 100644 index 589b23c3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortShortHashMap.java +++ /dev/null @@ -1,1080 +0,0 @@ -package com.carrotsearch.hppc; - -import static com.carrotsearch.hppc.Containers.*; -import static com.carrotsearch.hppc.HashContainers.*; - -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import java.util.*; - -/** - * A hash map of short to short, implemented using open addressing with - * linear probing for collision resolution. - * - * @see HPPC interfaces diagram - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeHashMap.java") -public class ShortShortHashMap implements ShortShortMap, Preallocable, Cloneable, Accountable { - - /** The array holding keys. */ - public short[] keys; - - /** The array holding values. */ - public short[] values; - - /** - * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use - * {@link #size()} instead). - * - * @see #size() - */ - protected int assigned; - - /** Mask for slot scans in {@link #keys}. */ - protected int mask; - - /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ - protected int resizeAt; - - /** Special treatment for the "empty slot" key marker. */ - protected boolean hasEmptyKey; - - /** The load factor for {@link #keys}. */ - protected double loadFactor; - - /** Seed used to ensure the hash iteration order is different from an iteration to another. */ - protected int iterationSeed; - - /** New instance with sane defaults. */ - public ShortShortHashMap() { - this(DEFAULT_EXPECTED_ELEMENTS); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortShortHashMap(int expectedElements) { - this(expectedElements, DEFAULT_LOAD_FACTOR); - } - - /** - * New instance with the provided defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause a rehash - * (inclusive). - * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full - * capacity) are rejected by {@link #verifyLoadFactor(double)}. - */ - public ShortShortHashMap(int expectedElements, double loadFactor) { - this.loadFactor = verifyLoadFactor(loadFactor); - iterationSeed = HashContainers.nextIterationSeed(); - ensureCapacity(expectedElements); - } - - /** Create a hash map from all key-value pairs of another container. */ - public ShortShortHashMap(ShortShortAssociativeContainer container) { - this(container.size()); - putAll(container); - } - - /** {@inheritDoc} */ - @Override - public short put(short key, short value) { - assert assigned < mask + 1; - - final int mask = this.mask; - if (((key) == 0)) { - short previousValue = hasEmptyKey ? values[mask + 1] : ((short) 0); - hasEmptyKey = true; - values[mask + 1] = value; - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final short previousValue = values[slot]; - values[slot] = value; - return previousValue; - } - slot = (slot + 1) & mask; - } - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(slot, key, value); - } else { - keys[slot] = key; - values[slot] = value; - } - - assigned++; - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int putAll(ShortShortAssociativeContainer container) { - final int count = size(); - for (ShortShortCursor c : container) { - put(c.key, c.value); - } - return size() - count; - } - - /** Puts all key/value pairs from a given iterable into this map. */ - @Override - public int putAll(Iterable iterable) { - final int count = size(); - for (ShortShortCursor c : iterable) { - put(c.key, c.value); - } - return size() - count; - } - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public short putOrAdd(short key, short putValue, short incrementValue) { - assert assigned < mask + 1; - - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - putValue = ((short) ((values[keyIndex]) + (incrementValue))); - indexReplace(keyIndex, putValue); - } else { - indexInsert(keyIndex, key, putValue); - } - return putValue; - } - - /** - * Adds incrementValue to any existing value for the given key or - * inserts incrementValue if key did not previously exist. - * - * @param key The key of the value to adjust. - * @param incrementValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - @Override - public short addTo(short key, short incrementValue) { - return putOrAdd(key, incrementValue, incrementValue); - } - - /** {@inheritDoc} */ - @Override - public short remove(short key) { - final int mask = this.mask; - if (((key) == 0)) { - if (!hasEmptyKey) { - return ((short) 0); - } - hasEmptyKey = false; - short previousValue = values[mask + 1]; - values[mask + 1] = ((short) 0); - return previousValue; - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - final short previousValue = values[slot]; - shiftConflictingKeys(slot); - return previousValue; - } - slot = (slot + 1) & mask; - } - - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortContainer other) { - final int before = size(); - - // Try to iterate over the smaller set of values or - // over the container that isn't implementing - // efficient contains() lookup. - - if (other.size() >= size() && other instanceof ShortLookupContainer) { - if (hasEmptyKey && other.contains(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && other.contains(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - } else { - for (ShortCursor c : other) { - remove(c.value); - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortShortPredicate predicate) { - final int before = size(); - - final int mask = this.mask; - - if (hasEmptyKey) { - if (predicate.apply(((short) 0), values[mask + 1])) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - } - - final short[] keys = this.keys; - final short[] values = this.values; - for (int slot = 0; slot <= mask; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public int removeAll(ShortPredicate predicate) { - final int before = size(); - - if (hasEmptyKey) { - if (predicate.apply(((short) 0))) { - hasEmptyKey = false; - values[mask + 1] = ((short) 0); - } - } - - final short[] keys = this.keys; - for (int slot = 0, max = this.mask; slot <= max; ) { - short existing; - if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { - // Shift, do not increment slot. - shiftConflictingKeys(slot); - } else { - slot++; - } - } - - return before - size(); - } - - /** {@inheritDoc} */ - @Override - public short get(short key) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : ((short) 0); - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return ((short) 0); - } - } - - /** {@inheritDoc} */ - @Override - public short getOrDefault(short key, short defaultValue) { - if (((key) == 0)) { - return hasEmptyKey ? values[mask + 1] : defaultValue; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return values[slot]; - } - slot = (slot + 1) & mask; - } - - return defaultValue; - } - } - - /** {@inheritDoc} */ - @Override - public boolean containsKey(short key) { - if (((key) == 0)) { - return hasEmptyKey; - } else { - final short[] keys = this.keys; - final int mask = this.mask; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return true; - } - slot = (slot + 1) & mask; - } - - return false; - } - } - - /** {@inheritDoc} */ - @Override - public int indexOf(short key) { - final int mask = this.mask; - if (((key) == 0)) { - return hasEmptyKey ? mask + 1 : ~(mask + 1); - } else { - final short[] keys = this.keys; - int slot = hashKey(key) & mask; - - short existing; - while (!((existing = keys[slot]) == 0)) { - if (((key) == (existing))) { - return slot; - } - slot = (slot + 1) & mask; - } - - return ~slot; - } - } - - /** {@inheritDoc} */ - @Override - public boolean indexExists(int index) { - assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); - - return index >= 0; - } - - /** {@inheritDoc} */ - @Override - public short indexGet(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - return values[index]; - } - - /** {@inheritDoc} */ - @Override - public short indexReplace(int index, short newValue) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - short previousValue = values[index]; - values[index] = newValue; - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void indexInsert(int index, short key, short value) { - assert index < 0 : "The index must not point at an existing key."; - - index = ~index; - if (((key) == 0)) { - assert index == mask + 1; - values[index] = value; - hasEmptyKey = true; - } else { - assert ((keys[index]) == 0); - - if (assigned == resizeAt) { - allocateThenInsertThenRehash(index, key, value); - } else { - keys[index] = key; - values[index] = value; - } - - assigned++; - } - } - - /** {@inheritDoc} */ - @Override - public short indexRemove(int index) { - assert index >= 0 : "The index must point at an existing key."; - assert index <= mask || (index == mask + 1 && hasEmptyKey); - - short previousValue = values[index]; - if (index > mask) { - assert index == mask + 1; - hasEmptyKey = false; - values[index] = ((short) 0); - } else { - shiftConflictingKeys(index); - } - return previousValue; - } - - /** {@inheritDoc} */ - @Override - public void clear() { - assigned = 0; - hasEmptyKey = false; - - Arrays.fill(keys, ((short) 0)); - } - - /** {@inheritDoc} */ - @Override - public void release() { - assigned = 0; - hasEmptyKey = false; - - keys = null; - values = null; - ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); - } - - /** {@inheritDoc} */ - @Override - public int size() { - return assigned + (hasEmptyKey ? 1 : 0); - } - - /** {@inheritDoc} */ - public boolean isEmpty() { - return size() == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = hasEmptyKey ? 0xDEADBEEF : 0; - for (ShortShortCursor c : this) { - h += BitMixer.mix(c.key) + BitMixer.mix(c.value); - } - return h; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return (this == obj) - || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); - } - - /** Return true if all keys of some other container exist in this container. */ - protected boolean equalElements(ShortShortHashMap other) { - if (other.size() != size()) { - return false; - } - - for (ShortShortCursor c : other) { - short key = c.key; - if (!containsKey(key) || !((c.value) == (get(key)))) { - return false; - } - } - - return true; - } - - /** - * Ensure this container can hold at least the given number of keys (entries) without resizing its - * buffers. - * - * @param expectedElements The total number of keys, inclusive. - */ - @Override - public void ensureCapacity(int expectedElements) { - if (expectedElements > resizeAt || keys == null) { - final short[] prevKeys = this.keys; - final short[] prevValues = this.values; - allocateBuffers(minBufferSize(expectedElements, loadFactor)); - if (prevKeys != null && !isEmpty()) { - rehash(prevKeys, prevValues); - } - } - } - - @Override - public long ramBytesAllocated() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowSizeOfArray(keys) - + RamUsageEstimator.shallowSizeOfArray(values); - } - - @Override - public long ramBytesUsed() { - // int: iterationSeed, assigned, mask, resizeAt - // double: loadFactor - // boolean: hasEmptyKey - return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER - + 4 * Integer.BYTES - + Double.BYTES - + 1 - + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) - + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); - } - - /** - * Provides the next iteration seed used to build the iteration starting slot and offset - * increment. This method does not need to be synchronized, what matters is that each thread gets - * a sequence of varying seeds. - */ - protected int nextIterationSeed() { - return iterationSeed = BitMixer.mixPhi(iterationSeed); - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public EntryIterator() { - cursor = new ShortShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortShortCursor fetch() { - final int mask = ShortShortHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.key = existing; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.key = ((short) 0); - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public Iterator iterator() { - return new EntryIterator(); - } - - /** {@inheritDoc} */ - @Override - public T forEach(T procedure) { - final short[] keys = this.keys; - final short[] values = this.values; - - if (hasEmptyKey) { - procedure.apply(((short) 0), values[mask + 1]); - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - procedure.apply(keys[slot], values[slot]); - } - } - - return procedure; - } - - /** {@inheritDoc} */ - @Override - public T forEach(T predicate) { - final short[] keys = this.keys; - final short[] values = this.values; - - if (hasEmptyKey) { - if (!predicate.apply(((short) 0), values[mask + 1])) { - return predicate; - } - } - - int seed = nextIterationSeed(); - int inc = iterationIncrement(seed); - for (int i = 0, mask = this.mask, slot = seed & mask; - i <= mask; - i++, slot = (slot + inc) & mask) { - if (!((keys[slot]) == 0)) { - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - } - - return predicate; - } - - /** - * Returns a specialized view of the keys of this associated container. The view additionally - * implements {@link ObjectLookupContainer}. - */ - public KeysContainer keys() { - return new KeysContainer(); - } - - /** A view of the keys inside this hash map. */ - public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { - private final ShortShortHashMap owner = ShortShortHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortShortProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortShortPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - return owner.removeAll(predicate); - } - - @Override - public int removeAll(final short e) { - if (owner.containsKey(e)) { - owner.remove(e); - return 1; - } else { - return 0; - } - } - } - ; - - /** An iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public KeysIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ShortShortHashMap.this.mask; - while (index <= mask) { - short existing; - index++; - slot = (slot + increment) & mask; - if (!((existing = keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = existing; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index++; - cursor.value = ((short) 0); - return cursor; - } - - return done(); - } - } - - /** - * @return Returns a container with all values stored in this map. - */ - @Override - public ShortCollection values() { - return new ValuesContainer(); - } - - /** A view over the set of values of this map. */ - private final class ValuesContainer extends AbstractShortCollection { - private final ShortShortHashMap owner = ShortShortHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(short value) { - for (ShortShortCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - for (ShortShortCursor c : owner) { - procedure.apply(c.value); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - for (ShortShortCursor c : owner) { - if (!predicate.apply(c.value)) { - break; - } - } - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final short e) { - return owner.removeAll((key, value) -> ((e) == (value))); - } - - @Override - public int removeAll(final ShortPredicate predicate) { - return owner.removeAll((key, value) -> predicate.apply(value)); - } - - @Override - public void clear() { - owner.clear(); - } - - @Override - public void release() { - owner.release(); - } - } - - /** An iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ShortCursor cursor; - private final int increment; - private int index; - private int slot; - - public ValuesIterator() { - cursor = new ShortCursor(); - int seed = nextIterationSeed(); - increment = iterationIncrement(seed); - slot = seed & mask; - } - - @Override - protected ShortCursor fetch() { - final int mask = ShortShortHashMap.this.mask; - while (index <= mask) { - index++; - slot = (slot + increment) & mask; - if (!((keys[slot]) == 0)) { - cursor.index = slot; - cursor.value = values[slot]; - return cursor; - } - } - - if (index == mask + 1 && hasEmptyKey) { - cursor.index = index; - cursor.value = values[index++]; - return cursor; - } - - return done(); - } - } - - /** {@inheritDoc} */ - @Override - public ShortShortHashMap clone() { - try { - - ShortShortHashMap cloned = (ShortShortHashMap) super.clone(); - cloned.keys = keys.clone(); - cloned.values = values.clone(); - cloned.hasEmptyKey = hasEmptyKey; - cloned.iterationSeed = HashContainers.nextIterationSeed(); - return cloned; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - /** Convert the contents of this map to a human-friendly string. */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append("["); - - boolean first = true; - for (ShortShortCursor cursor : this) { - if (!first) { - buffer.append(", "); - } - buffer.append(cursor.key); - buffer.append("=>"); - buffer.append(cursor.value); - first = false; - } - buffer.append("]"); - return buffer.toString(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); - } - - /** Creates a hash map from two index-aligned arrays of key-value pairs. */ - public static ShortShortHashMap from(short[] keys, short[] values) { - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Arrays of keys and values must have an identical length."); - } - - ShortShortHashMap map = new ShortShortHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - map.put(keys[i], values[i]); - } - - return map; - } - - /** - * Returns a hash code for the given key. - * - *

The output from this function should evenly distribute keys across the entire integer range. - */ - protected int hashKey(short key) { - assert !((key) == 0); // Handled as a special case (empty slot marker). - return BitMixer.mixPhi(key); - } - - /** - * Validate load factor range and return it. Override and suppress if you need insane load - * factors. - */ - protected double verifyLoadFactor(double loadFactor) { - checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); - return loadFactor; - } - - /** Rehash from old buffers to new buffers. */ - protected void rehash(short[] fromKeys, short[] fromValues) { - assert fromKeys.length == fromValues.length - && HashContainers.checkPowerOfTwo(fromKeys.length - 1); - - // Rehash all stored key/value pairs into the new buffers. - final short[] keys = this.keys; - final short[] values = this.values; - final int mask = this.mask; - short existing; - - // Copy the zero element's slot, then rehash everything else. - int from = fromKeys.length - 1; - keys[keys.length - 1] = fromKeys[from]; - values[values.length - 1] = fromValues[from]; - while (--from >= 0) { - if (!((existing = fromKeys[from]) == 0)) { - int slot = hashKey(existing) & mask; - while (!((keys[slot]) == 0)) { - slot = (slot + 1) & mask; - } - keys[slot] = existing; - values[slot] = fromValues[from]; - } - } - } - - /** - * Allocate new internal buffers. This method attempts to allocate and assign internal buffers - * atomically (either allocations succeed or not). - */ - protected void allocateBuffers(int arraySize) { - assert Integer.bitCount(arraySize) == 1; - - // Ensure no change is done if we hit an OOM. - short[] prevKeys = this.keys; - short[] prevValues = this.values; - try { - int emptyElementSlot = 1; - this.keys = (new short[arraySize + emptyElementSlot]); - this.values = (new short[arraySize + emptyElementSlot]); - } catch (OutOfMemoryError e) { - this.keys = prevKeys; - this.values = prevValues; - throw new BufferAllocationException( - "Not enough memory to allocate buffers for rehashing: %,d -> %,d", - e, this.mask + 1, arraySize); - } - - this.resizeAt = expandAtCount(arraySize, loadFactor); - this.mask = arraySize - 1; - } - - /** - * This method is invoked when there is a new key/ value pair to be inserted into the buffers but - * there is not enough empty slots to do so. - * - *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we - * assign the pending element to the previous buffer (possibly violating the invariant of having - * at least one empty slot) and rehash all keys, substituting new buffers at the end. - */ - protected void allocateThenInsertThenRehash(int slot, short pendingKey, short pendingValue) { - assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); - - // Try to allocate new buffers first. If we OOM, we leave in a consistent state. - final short[] prevKeys = this.keys; - final short[] prevValues = this.values; - allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); - assert this.keys.length > prevKeys.length; - - // We have succeeded at allocating new data so insert the pending key/value at - // the free slot in the old arrays before rehashing. - prevKeys[slot] = pendingKey; - prevValues[slot] = pendingValue; - - // Rehash old keys, including the pending key. - rehash(prevKeys, prevValues); - } - - /** - * Shift all the slot-conflicting keys and values allocated to (and including) slot. - */ - protected void shiftConflictingKeys(int gapSlot) { - final short[] keys = this.keys; - final short[] values = this.values; - final int mask = this.mask; - - // Perform shifts of conflicting keys to fill in the gap. - int distance = 0; - while (true) { - final int slot = (gapSlot + (++distance)) & mask; - final short existing = keys[slot]; - if (((existing) == 0)) { - break; - } - - final int idealSlot = hashKey(existing); - final int shift = (slot - idealSlot) & mask; - if (shift >= distance) { - // Entry at this position was originally at or before the gap slot. - // Move the conflict-shifted entry to the gap's position and repeat the procedure - // for any entries to the right of the current position, treating it - // as the new gap. - keys[gapSlot] = existing; - values[gapSlot] = values[slot]; - gapSlot = slot; - distance = 0; - } - } - - // Mark the last found gap slot without a conflict as empty. - keys[gapSlot] = ((short) 0); - values[gapSlot] = ((short) 0); - assigned--; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortShortMap.java b/sources/main/java/com/carrotsearch/hppc/ShortShortMap.java deleted file mode 100644 index d90c602e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortShortMap.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortShortCursor; - -/** An associative container with unique binding from keys to a single value. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") -public interface ShortShortMap extends ShortShortAssociativeContainer { - /** - * @return Returns the value associated with the given key or the default value for the value - * type, if the key is not associated with any value. For numeric value types, this default - * value is 0, for object types it is {@code null}. - */ - public short get(short key); - - /** - * @return Returns the value associated with the given key or the provided default value if the - * key is not associated with any value. - */ - public short getOrDefault(short key, short defaultValue); - - /** - * Place a given key and value in the container. - * - * @return The value previously stored under the given key in the map is returned. - */ - public short put(short key, short value); - - /** - * If the specified key is not already associated with a value, associates it with the given - * value. - * - * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, - * {@code false} otherwise. - */ - public default boolean putIfAbsent(short key, short value) { - int keyIndex = indexOf(key); - if (indexExists(keyIndex)) { - return false; - } else { - indexInsert(keyIndex, key, value); - return true; - } - } - - /** - * Puts all keys from another container to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(ShortShortAssociativeContainer container); - - /** - * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if - * such keys are present. - * - * @return Returns the number of keys added to the map as a result of this call (not previously - * present in the map). Values of existing keys are overwritten. - */ - public int putAll(Iterable iterable); - - /** - * If key exists, putValue is inserted into the map, otherwise any - * existing value is incremented by additionValue. - * - * @param key The key of the value to adjust. - * @param putValue The value to put if key does not exist. - * @param incrementValue The value to add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public short putOrAdd(short key, short putValue, short incrementValue); - - /** - * An equivalent of calling - * - *

-   * putOrAdd(key, additionValue, additionValue);
-   * 
- * - * @param key The key of the value to adjust. - * @param additionValue The value to put or add to the existing value if key exists. - * @return Returns the current value associated with key (after changes). - */ - public short addTo(short key, short additionValue); - - /** - * Remove all values at the given key. The default value for the key type is returned if the value - * does not exist in the map. - */ - public short remove(short key); - - /** - * Compares the specified object with this set for equality. Returns {@code true} if and only if - * the specified object is also a {@link ShortShortMap} and both objects contains exactly the same - * key-value pairs. - */ - public boolean equals(Object obj); - - /** - * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash - * codes of keys and values stored within the set). Because sum is commutative, this ensures - * that different order of elements in a set does not affect the hash code. - */ - public int hashCode(); - - /** - * Returns a logical "index" of a given key that can be used to speed up follow-up value setters - * or getters in certain scenarios (conditional logic). - * - *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) - * contiguous. - * - *

The index is valid only between map modifications (it will not be affected by read-only - * operations like iteration or value retrievals). - * - * @see #indexExists - * @see #indexGet - * @see #indexInsert - * @see #indexReplace - * @param key The key to locate in the map. - * @return A non-negative value of the logical "index" of the key in the map or a negative value - * if the key did not exist. - */ - public int indexOf(short key); - - /** - * @see #indexOf - * @param index The index of a given key, as returned from {@link #indexOf}. - * @return Returns true if the index corresponds to an existing key or false - * otherwise. This is equivalent to checking whether the index is a positive value (existing - * keys) or a negative value (non-existing keys). - */ - public boolean indexExists(int index); - - /** - * Returns the value associated with an existing key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the value currently associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexGet(int index); - - /** - * Replaces the value associated with an existing key and returns any previous value stored for - * that key. - * - * @see #indexOf - * @param index The index of an existing key. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexReplace(int index, short newValue); - - /** - * Inserts a key-value pair for a key that is not present in the map. This method may help in - * avoiding double recalculation of the key's hash. - * - * @see #indexOf - * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. - * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. - */ - public void indexInsert(int index, short key, short value); - - /** - * Removes a key-value pair at an index previously acquired from {@link #indexOf}. - * - * @see #indexOf - * @param index The index of the key to remove, as returned from {@link #indexOf}. - * @return Returns the previous value associated with the key. - * @throws AssertionError If assertions are enabled and the index does not correspond to an - * existing key. - */ - public short indexRemove(int index); - - /** - * Clear all keys and values in the container. - * - * @see #release() - */ - public void clear(); - - /** - * Removes all elements from the collection and additionally releases any internal buffers. - * Typically, if the object is to be reused, a simple {@link #clear()} should be a better - * alternative since it'll avoid reallocation. - * - * @see #clear() - */ - public void release(); - - /** - * Visually depict the distribution of keys. - * - * @param characters The number of characters to "squeeze" the entire buffer into. - * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal - * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything - * between 1 and 9 is between. - */ - public String visualizeKeyDistribution(int characters); -} diff --git a/sources/main/java/com/carrotsearch/hppc/ShortStack.java b/sources/main/java/com/carrotsearch/hppc/ShortStack.java deleted file mode 100644 index 2c972c32..00000000 --- a/sources/main/java/com/carrotsearch/hppc/ShortStack.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.cursors.ShortCursor; - -/** - * A subclass of {@link ShortArrayList} adding stack-related utility methods. The top of the stack - * is at the {@link #size()} - 1 element. - */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") -public class ShortStack extends ShortArrayList { - /** New instance with sane defaults. */ - public ShortStack() { - super(); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - */ - public ShortStack(int expectedElements) { - super(expectedElements); - } - - /** - * New instance with sane defaults. - * - * @param expectedElements The expected number of elements guaranteed not to cause buffer - * expansion (inclusive). - * @param resizer Underlying buffer sizing strategy. - */ - public ShortStack(int expectedElements, ArraySizingStrategy resizer) { - super(expectedElements, resizer); - } - - /** Create a stack by pushing all elements of another container to it. */ - public ShortStack(ShortContainer container) { - super(container); - } - - /** Adds one short to the stack. */ - public void push(short e1) { - ensureBufferSpace(1); - buffer[elementsCount++] = e1; - } - - /** Adds two shorts to the stack. */ - public void push(short e1, short e2) { - ensureBufferSpace(2); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - } - - /** Adds three shorts to the stack. */ - public void push(short e1, short e2, short e3) { - ensureBufferSpace(3); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - } - - /** Adds four shorts to the stack. */ - public void push(short e1, short e2, short e3, short e4) { - ensureBufferSpace(4); - buffer[elementsCount++] = e1; - buffer[elementsCount++] = e2; - buffer[elementsCount++] = e3; - buffer[elementsCount++] = e4; - } - - /** Add a range of array elements to the stack. */ - public void push(short[] elements, int start, int len) { - assert start >= 0 && len >= 0; - - ensureBufferSpace(len); - System.arraycopy(elements, start, buffer, elementsCount, len); - elementsCount += len; - } - - /** - * Vararg-signature method for pushing elements at the top of the stack. - * - *

This method is handy, but costly if used in tight loops (anonymous array passing) - */ - public final void push(short... elements) { - push(elements, 0, elements.length); - } - - /** Pushes all elements from another container to the top of the stack. */ - public int pushAll(ShortContainer container) { - return addAll(container); - } - - /** Pushes all elements from another iterable to the top of the stack. */ - public int pushAll(Iterable iterable) { - return addAll(iterable); - } - - /** Discard an arbitrary number of elements from the top of the stack. */ - public void discard(int count) { - assert elementsCount >= count; - - elementsCount -= count; - } - - /** Discard the top element from the stack. */ - public void discard() { - assert elementsCount > 0; - - elementsCount--; - } - - /** Remove the top element from the stack and return it. */ - public short pop() { - return removeLast(); - } - - /** Peek at the top element on the stack. */ - public short peek() { - assert elementsCount > 0; - return buffer[elementsCount - 1]; - } - - /** Create a stack by pushing a variable number of arguments to it. */ - public static ShortStack from(short... elements) { - final ShortStack stack = new ShortStack(elements.length); - stack.push(elements); - return stack; - } - - /** {@inheritDoc} */ - @Override - public ShortStack clone() { - return (ShortStack) super.clone(); - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharByteHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationCharByteHashMap.java deleted file mode 100644 index 4e0da79c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharByteHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link CharByteHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link CharByteHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationCharByteHashMap implements CharByteMap { - public final CharByteHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationCharByteHashMap(CharByteHashMap delegate, CharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationCharByteHashMap(CharByteHashMap delegate, CharByteComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final char[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - char[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharByteComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final char[] keys = delegate.keys; - final byte[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(char key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(CharContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharBytePredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final byte[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final byte[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public CharCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ByteContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public byte get(char key) { - return delegate.get(key); - } - - @Override - public byte getOrDefault(char key, byte defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public byte put(char key, byte value) { - throw readOnlyException(); - } - - @Override - public int putAll(CharByteAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public byte putOrAdd(char key, byte putValue, byte incrementValue) { - throw readOnlyException(); - } - - @Override - public byte addTo(char key, byte additionValue) { - throw readOnlyException(); - } - - @Override - public byte remove(char key) { - throw readOnlyException(); - } - - @Override - public int indexOf(char key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public byte indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public byte indexReplace(int index, byte newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, char key, byte value) { - throw readOnlyException(); - } - - @Override - public byte indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharByteCursor cursor = new CharByteCursor(); - private int index; - - @Override - protected CharByteCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final SortedIterationCharByteHashMap owner = SortedIterationCharByteHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharByteProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharBytePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractByteCollection { - private final SortedIterationCharByteHashMap owner = SortedIterationCharByteHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(byte value) { - for (CharByteCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((CharByteProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((CharBytePredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final byte e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final BytePredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ByteCursor cursor = new ByteCursor(); - private int index; - - @Override - protected ByteCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharCharHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationCharCharHashMap.java deleted file mode 100644 index e5f5017d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharCharHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link CharCharHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link CharCharHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationCharCharHashMap implements CharCharMap { - public final CharCharHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationCharCharHashMap(CharCharHashMap delegate, CharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationCharCharHashMap(CharCharHashMap delegate, CharCharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final char[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - char[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharCharComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final char[] keys = delegate.keys; - final char[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(char key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(CharContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharCharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final char[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final char[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public CharCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public CharContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public char get(char key) { - return delegate.get(key); - } - - @Override - public char getOrDefault(char key, char defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public char put(char key, char value) { - throw readOnlyException(); - } - - @Override - public int putAll(CharCharAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public char putOrAdd(char key, char putValue, char incrementValue) { - throw readOnlyException(); - } - - @Override - public char addTo(char key, char additionValue) { - throw readOnlyException(); - } - - @Override - public char remove(char key) { - throw readOnlyException(); - } - - @Override - public int indexOf(char key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public char indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public char indexReplace(int index, char newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, char key, char value) { - throw readOnlyException(); - } - - @Override - public char indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharCharCursor cursor = new CharCharCursor(); - private int index; - - @Override - protected CharCharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final SortedIterationCharCharHashMap owner = SortedIterationCharCharHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharCharProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharCharPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractCharCollection { - private final SortedIterationCharCharHashMap owner = SortedIterationCharCharHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(char value) { - for (CharCharCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((CharCharProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((CharCharPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharDoubleHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationCharDoubleHashMap.java deleted file mode 100644 index 0d54399c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharDoubleHashMap.java +++ /dev/null @@ -1,441 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link CharDoubleHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link CharDoubleHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationCharDoubleHashMap implements CharDoubleMap { - public final CharDoubleHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationCharDoubleHashMap(CharDoubleHashMap delegate, CharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationCharDoubleHashMap( - CharDoubleHashMap delegate, CharDoubleComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final char[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - char[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharDoubleComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final char[] keys = delegate.keys; - final double[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(char key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(CharContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharDoublePredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final double[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final double[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public CharCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public DoubleContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public double get(char key) { - return delegate.get(key); - } - - @Override - public double getOrDefault(char key, double defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public double put(char key, double value) { - throw readOnlyException(); - } - - @Override - public int putAll(CharDoubleAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public double putOrAdd(char key, double putValue, double incrementValue) { - throw readOnlyException(); - } - - @Override - public double addTo(char key, double additionValue) { - throw readOnlyException(); - } - - @Override - public double remove(char key) { - throw readOnlyException(); - } - - @Override - public int indexOf(char key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public double indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public double indexReplace(int index, double newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, char key, double value) { - throw readOnlyException(); - } - - @Override - public double indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharDoubleCursor cursor = new CharDoubleCursor(); - private int index; - - @Override - protected CharDoubleCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final SortedIterationCharDoubleHashMap owner = SortedIterationCharDoubleHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharDoubleProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharDoublePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractDoubleCollection { - private final SortedIterationCharDoubleHashMap owner = SortedIterationCharDoubleHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(double value) { - for (CharDoubleCursor c : owner) { - if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((CharDoubleProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((CharDoublePredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final double e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final DoublePredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final DoubleCursor cursor = new DoubleCursor(); - private int index; - - @Override - protected DoubleCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharFloatHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationCharFloatHashMap.java deleted file mode 100644 index 90c227ef..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharFloatHashMap.java +++ /dev/null @@ -1,441 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link CharFloatHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link CharFloatHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationCharFloatHashMap implements CharFloatMap { - public final CharFloatHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationCharFloatHashMap(CharFloatHashMap delegate, CharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationCharFloatHashMap( - CharFloatHashMap delegate, CharFloatComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final char[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - char[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharFloatComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final char[] keys = delegate.keys; - final float[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(char key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(CharContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharFloatPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final float[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final float[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public CharCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public FloatContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public float get(char key) { - return delegate.get(key); - } - - @Override - public float getOrDefault(char key, float defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public float put(char key, float value) { - throw readOnlyException(); - } - - @Override - public int putAll(CharFloatAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public float putOrAdd(char key, float putValue, float incrementValue) { - throw readOnlyException(); - } - - @Override - public float addTo(char key, float additionValue) { - throw readOnlyException(); - } - - @Override - public float remove(char key) { - throw readOnlyException(); - } - - @Override - public int indexOf(char key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public float indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public float indexReplace(int index, float newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, char key, float value) { - throw readOnlyException(); - } - - @Override - public float indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharFloatCursor cursor = new CharFloatCursor(); - private int index; - - @Override - protected CharFloatCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final SortedIterationCharFloatHashMap owner = SortedIterationCharFloatHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharFloatProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharFloatPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractFloatCollection { - private final SortedIterationCharFloatHashMap owner = SortedIterationCharFloatHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(float value) { - for (CharFloatCursor c : owner) { - if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((CharFloatProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((CharFloatPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final float e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final FloatPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final FloatCursor cursor = new FloatCursor(); - private int index; - - @Override - protected FloatCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharIntHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationCharIntHashMap.java deleted file mode 100644 index dde200f4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharIntHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link CharIntHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link CharIntHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationCharIntHashMap implements CharIntMap { - public final CharIntHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationCharIntHashMap(CharIntHashMap delegate, CharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationCharIntHashMap(CharIntHashMap delegate, CharIntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final char[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - char[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharIntComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final char[] keys = delegate.keys; - final int[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(char key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(CharContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharIntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final int[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final int[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public CharCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public IntContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public int get(char key) { - return delegate.get(key); - } - - @Override - public int getOrDefault(char key, int defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public int put(char key, int value) { - throw readOnlyException(); - } - - @Override - public int putAll(CharIntAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public int putOrAdd(char key, int putValue, int incrementValue) { - throw readOnlyException(); - } - - @Override - public int addTo(char key, int additionValue) { - throw readOnlyException(); - } - - @Override - public int remove(char key) { - throw readOnlyException(); - } - - @Override - public int indexOf(char key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public int indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public int indexReplace(int index, int newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, char key, int value) { - throw readOnlyException(); - } - - @Override - public int indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharIntCursor cursor = new CharIntCursor(); - private int index; - - @Override - protected CharIntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final SortedIterationCharIntHashMap owner = SortedIterationCharIntHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharIntProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharIntPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractIntCollection { - private final SortedIterationCharIntHashMap owner = SortedIterationCharIntHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(int value) { - for (CharIntCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((CharIntProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((CharIntPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharLongHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationCharLongHashMap.java deleted file mode 100644 index 76ec360d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharLongHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link CharLongHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link CharLongHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationCharLongHashMap implements CharLongMap { - public final CharLongHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationCharLongHashMap(CharLongHashMap delegate, CharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationCharLongHashMap(CharLongHashMap delegate, CharLongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final char[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - char[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharLongComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final char[] keys = delegate.keys; - final long[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(char key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(CharContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharLongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final long[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final long[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public CharCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public LongContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public long get(char key) { - return delegate.get(key); - } - - @Override - public long getOrDefault(char key, long defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public long put(char key, long value) { - throw readOnlyException(); - } - - @Override - public int putAll(CharLongAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public long putOrAdd(char key, long putValue, long incrementValue) { - throw readOnlyException(); - } - - @Override - public long addTo(char key, long additionValue) { - throw readOnlyException(); - } - - @Override - public long remove(char key) { - throw readOnlyException(); - } - - @Override - public int indexOf(char key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public long indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public long indexReplace(int index, long newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, char key, long value) { - throw readOnlyException(); - } - - @Override - public long indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharLongCursor cursor = new CharLongCursor(); - private int index; - - @Override - protected CharLongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final SortedIterationCharLongHashMap owner = SortedIterationCharLongHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharLongProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharLongPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractLongCollection { - private final SortedIterationCharLongHashMap owner = SortedIterationCharLongHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(long value) { - for (CharLongCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((CharLongProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((CharLongPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharObjectHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationCharObjectHashMap.java deleted file mode 100644 index b4eef4b9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharObjectHashMap.java +++ /dev/null @@ -1,435 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link CharObjectHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link CharObjectHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationCharObjectHashMap implements CharObjectMap { - public final CharObjectHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationCharObjectHashMap( - CharObjectHashMap delegate, CharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationCharObjectHashMap( - CharObjectHashMap delegate, CharObjectComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final char[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - char[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharObjectComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final char[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(char key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(CharContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public CharCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ObjectContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public VType get(char key) { - return delegate.get(key); - } - - @Override - public VType getOrDefault(char key, VType defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public VType put(char key, VType value) { - throw readOnlyException(); - } - - @Override - public int putAll(CharObjectAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public VType remove(char key) { - throw readOnlyException(); - } - - @Override - public int indexOf(char key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public VType indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public VType indexReplace(int index, VType newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, char key, VType value) { - throw readOnlyException(); - } - - @Override - public VType indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final CharObjectCursor cursor = new CharObjectCursor(); - private int index; - - @Override - protected CharObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = (VType) delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final SortedIterationCharObjectHashMap owner = - SortedIterationCharObjectHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharObjectProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharObjectPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractObjectCollection { - private final SortedIterationCharObjectHashMap owner = - SortedIterationCharObjectHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(VType value) { - for (CharObjectCursor c : owner) { - if (java.util.Objects.equals(value, c.value)) { - return true; - } - } - return false; - } - - @Override - public > T forEach(T procedure) { - owner.forEach((CharObjectProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public > T forEach(T predicate) { - owner.forEach((CharObjectPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator> iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final VType e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (VType) delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharShortHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationCharShortHashMap.java deleted file mode 100644 index 8097e0c0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationCharShortHashMap.java +++ /dev/null @@ -1,441 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link CharShortHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link CharShortHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationCharShortHashMap implements CharShortMap { - public final CharShortHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationCharShortHashMap(CharShortHashMap delegate, CharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationCharShortHashMap( - CharShortHashMap delegate, CharShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final char[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - char[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, CharShortComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final char[] keys = delegate.keys; - final short[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(char key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(CharContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(CharShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final short[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final char[] keys = delegate.keys; - final short[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public CharCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ShortContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public short get(char key) { - return delegate.get(key); - } - - @Override - public short getOrDefault(char key, short defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public short put(char key, short value) { - throw readOnlyException(); - } - - @Override - public int putAll(CharShortAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public short putOrAdd(char key, short putValue, short incrementValue) { - throw readOnlyException(); - } - - @Override - public short addTo(char key, short additionValue) { - throw readOnlyException(); - } - - @Override - public short remove(char key) { - throw readOnlyException(); - } - - @Override - public int indexOf(char key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public short indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public short indexReplace(int index, short newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, char key, short value) { - throw readOnlyException(); - } - - @Override - public short indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final CharShortCursor cursor = new CharShortCursor(); - private int index; - - @Override - protected CharShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { - private final SortedIterationCharShortHashMap owner = SortedIterationCharShortHashMap.this; - - @Override - public boolean contains(char e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((CharShortProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((CharShortPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractShortCollection { - private final SortedIterationCharShortHashMap owner = SortedIterationCharShortHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(short value) { - for (CharShortCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((CharShortProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((CharShortPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntByteHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationIntByteHashMap.java deleted file mode 100644 index ff9ca502..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntByteHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link IntByteHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link IntByteHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationIntByteHashMap implements IntByteMap { - public final IntByteHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationIntByteHashMap(IntByteHashMap delegate, IntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationIntByteHashMap(IntByteHashMap delegate, IntByteComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final int[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - int[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntByteComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final int[] keys = delegate.keys; - final byte[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(int key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(IntContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntBytePredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final byte[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final byte[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public IntCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ByteContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public byte get(int key) { - return delegate.get(key); - } - - @Override - public byte getOrDefault(int key, byte defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public byte put(int key, byte value) { - throw readOnlyException(); - } - - @Override - public int putAll(IntByteAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public byte putOrAdd(int key, byte putValue, byte incrementValue) { - throw readOnlyException(); - } - - @Override - public byte addTo(int key, byte additionValue) { - throw readOnlyException(); - } - - @Override - public byte remove(int key) { - throw readOnlyException(); - } - - @Override - public int indexOf(int key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public byte indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public byte indexReplace(int index, byte newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, int key, byte value) { - throw readOnlyException(); - } - - @Override - public byte indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntByteCursor cursor = new IntByteCursor(); - private int index; - - @Override - protected IntByteCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final SortedIterationIntByteHashMap owner = SortedIterationIntByteHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntByteProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntBytePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractByteCollection { - private final SortedIterationIntByteHashMap owner = SortedIterationIntByteHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(byte value) { - for (IntByteCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((IntByteProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((IntBytePredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final byte e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final BytePredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ByteCursor cursor = new ByteCursor(); - private int index; - - @Override - protected ByteCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntCharHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationIntCharHashMap.java deleted file mode 100644 index c9190720..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntCharHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link IntCharHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link IntCharHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationIntCharHashMap implements IntCharMap { - public final IntCharHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationIntCharHashMap(IntCharHashMap delegate, IntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationIntCharHashMap(IntCharHashMap delegate, IntCharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final int[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - int[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntCharComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final int[] keys = delegate.keys; - final char[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(int key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(IntContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntCharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final char[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final char[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public IntCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public CharContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public char get(int key) { - return delegate.get(key); - } - - @Override - public char getOrDefault(int key, char defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public char put(int key, char value) { - throw readOnlyException(); - } - - @Override - public int putAll(IntCharAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public char putOrAdd(int key, char putValue, char incrementValue) { - throw readOnlyException(); - } - - @Override - public char addTo(int key, char additionValue) { - throw readOnlyException(); - } - - @Override - public char remove(int key) { - throw readOnlyException(); - } - - @Override - public int indexOf(int key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public char indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public char indexReplace(int index, char newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, int key, char value) { - throw readOnlyException(); - } - - @Override - public char indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntCharCursor cursor = new IntCharCursor(); - private int index; - - @Override - protected IntCharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final SortedIterationIntCharHashMap owner = SortedIterationIntCharHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntCharProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntCharPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractCharCollection { - private final SortedIterationIntCharHashMap owner = SortedIterationIntCharHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(char value) { - for (IntCharCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((IntCharProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((IntCharPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntDoubleHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationIntDoubleHashMap.java deleted file mode 100644 index 107abe8f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntDoubleHashMap.java +++ /dev/null @@ -1,441 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link IntDoubleHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link IntDoubleHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationIntDoubleHashMap implements IntDoubleMap { - public final IntDoubleHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationIntDoubleHashMap(IntDoubleHashMap delegate, IntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationIntDoubleHashMap( - IntDoubleHashMap delegate, IntDoubleComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final int[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - int[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntDoubleComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final int[] keys = delegate.keys; - final double[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(int key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(IntContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntDoublePredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final double[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final double[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public IntCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public DoubleContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public double get(int key) { - return delegate.get(key); - } - - @Override - public double getOrDefault(int key, double defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public double put(int key, double value) { - throw readOnlyException(); - } - - @Override - public int putAll(IntDoubleAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public double putOrAdd(int key, double putValue, double incrementValue) { - throw readOnlyException(); - } - - @Override - public double addTo(int key, double additionValue) { - throw readOnlyException(); - } - - @Override - public double remove(int key) { - throw readOnlyException(); - } - - @Override - public int indexOf(int key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public double indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public double indexReplace(int index, double newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, int key, double value) { - throw readOnlyException(); - } - - @Override - public double indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntDoubleCursor cursor = new IntDoubleCursor(); - private int index; - - @Override - protected IntDoubleCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final SortedIterationIntDoubleHashMap owner = SortedIterationIntDoubleHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntDoubleProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntDoublePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractDoubleCollection { - private final SortedIterationIntDoubleHashMap owner = SortedIterationIntDoubleHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(double value) { - for (IntDoubleCursor c : owner) { - if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((IntDoubleProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((IntDoublePredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final double e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final DoublePredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final DoubleCursor cursor = new DoubleCursor(); - private int index; - - @Override - protected DoubleCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntFloatHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationIntFloatHashMap.java deleted file mode 100644 index ff98b064..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntFloatHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link IntFloatHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link IntFloatHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationIntFloatHashMap implements IntFloatMap { - public final IntFloatHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationIntFloatHashMap(IntFloatHashMap delegate, IntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationIntFloatHashMap(IntFloatHashMap delegate, IntFloatComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final int[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - int[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntFloatComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final int[] keys = delegate.keys; - final float[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(int key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(IntContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntFloatPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final float[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final float[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public IntCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public FloatContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public float get(int key) { - return delegate.get(key); - } - - @Override - public float getOrDefault(int key, float defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public float put(int key, float value) { - throw readOnlyException(); - } - - @Override - public int putAll(IntFloatAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public float putOrAdd(int key, float putValue, float incrementValue) { - throw readOnlyException(); - } - - @Override - public float addTo(int key, float additionValue) { - throw readOnlyException(); - } - - @Override - public float remove(int key) { - throw readOnlyException(); - } - - @Override - public int indexOf(int key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public float indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public float indexReplace(int index, float newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, int key, float value) { - throw readOnlyException(); - } - - @Override - public float indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntFloatCursor cursor = new IntFloatCursor(); - private int index; - - @Override - protected IntFloatCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final SortedIterationIntFloatHashMap owner = SortedIterationIntFloatHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntFloatProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntFloatPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractFloatCollection { - private final SortedIterationIntFloatHashMap owner = SortedIterationIntFloatHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(float value) { - for (IntFloatCursor c : owner) { - if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((IntFloatProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((IntFloatPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final float e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final FloatPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final FloatCursor cursor = new FloatCursor(); - private int index; - - @Override - protected FloatCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntIntHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationIntIntHashMap.java deleted file mode 100644 index 8cb4c22c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntIntHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link IntIntHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link IntIntHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationIntIntHashMap implements IntIntMap { - public final IntIntHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationIntIntHashMap(IntIntHashMap delegate, IntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationIntIntHashMap(IntIntHashMap delegate, IntIntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final int[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - int[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntIntComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final int[] keys = delegate.keys; - final int[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(int key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(IntContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntIntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final int[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final int[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public IntCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public IntContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public int get(int key) { - return delegate.get(key); - } - - @Override - public int getOrDefault(int key, int defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public int put(int key, int value) { - throw readOnlyException(); - } - - @Override - public int putAll(IntIntAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public int putOrAdd(int key, int putValue, int incrementValue) { - throw readOnlyException(); - } - - @Override - public int addTo(int key, int additionValue) { - throw readOnlyException(); - } - - @Override - public int remove(int key) { - throw readOnlyException(); - } - - @Override - public int indexOf(int key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public int indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public int indexReplace(int index, int newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, int key, int value) { - throw readOnlyException(); - } - - @Override - public int indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntIntCursor cursor = new IntIntCursor(); - private int index; - - @Override - protected IntIntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final SortedIterationIntIntHashMap owner = SortedIterationIntIntHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntIntProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntIntPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractIntCollection { - private final SortedIterationIntIntHashMap owner = SortedIterationIntIntHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(int value) { - for (IntIntCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((IntIntProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((IntIntPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntLongHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationIntLongHashMap.java deleted file mode 100644 index bbbfb306..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntLongHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link IntLongHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link IntLongHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationIntLongHashMap implements IntLongMap { - public final IntLongHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationIntLongHashMap(IntLongHashMap delegate, IntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationIntLongHashMap(IntLongHashMap delegate, IntLongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final int[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - int[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntLongComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final int[] keys = delegate.keys; - final long[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(int key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(IntContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntLongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final long[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final long[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public IntCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public LongContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public long get(int key) { - return delegate.get(key); - } - - @Override - public long getOrDefault(int key, long defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public long put(int key, long value) { - throw readOnlyException(); - } - - @Override - public int putAll(IntLongAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public long putOrAdd(int key, long putValue, long incrementValue) { - throw readOnlyException(); - } - - @Override - public long addTo(int key, long additionValue) { - throw readOnlyException(); - } - - @Override - public long remove(int key) { - throw readOnlyException(); - } - - @Override - public int indexOf(int key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public long indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public long indexReplace(int index, long newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, int key, long value) { - throw readOnlyException(); - } - - @Override - public long indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntLongCursor cursor = new IntLongCursor(); - private int index; - - @Override - protected IntLongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final SortedIterationIntLongHashMap owner = SortedIterationIntLongHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntLongProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntLongPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractLongCollection { - private final SortedIterationIntLongHashMap owner = SortedIterationIntLongHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(long value) { - for (IntLongCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((IntLongProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((IntLongPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntObjectHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationIntObjectHashMap.java deleted file mode 100644 index cd8591ef..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntObjectHashMap.java +++ /dev/null @@ -1,435 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link IntObjectHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link IntObjectHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationIntObjectHashMap implements IntObjectMap { - public final IntObjectHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationIntObjectHashMap( - IntObjectHashMap delegate, IntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationIntObjectHashMap( - IntObjectHashMap delegate, IntObjectComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final int[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - int[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntObjectComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final int[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(int key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(IntContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public IntCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ObjectContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public VType get(int key) { - return delegate.get(key); - } - - @Override - public VType getOrDefault(int key, VType defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public VType put(int key, VType value) { - throw readOnlyException(); - } - - @Override - public int putAll(IntObjectAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public VType remove(int key) { - throw readOnlyException(); - } - - @Override - public int indexOf(int key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public VType indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public VType indexReplace(int index, VType newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, int key, VType value) { - throw readOnlyException(); - } - - @Override - public VType indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final IntObjectCursor cursor = new IntObjectCursor(); - private int index; - - @Override - protected IntObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = (VType) delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final SortedIterationIntObjectHashMap owner = - SortedIterationIntObjectHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntObjectProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntObjectPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractObjectCollection { - private final SortedIterationIntObjectHashMap owner = - SortedIterationIntObjectHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(VType value) { - for (IntObjectCursor c : owner) { - if (java.util.Objects.equals(value, c.value)) { - return true; - } - } - return false; - } - - @Override - public > T forEach(T procedure) { - owner.forEach((IntObjectProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public > T forEach(T predicate) { - owner.forEach((IntObjectPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator> iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final VType e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (VType) delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntShortHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationIntShortHashMap.java deleted file mode 100644 index 243bf989..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationIntShortHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link IntShortHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link IntShortHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationIntShortHashMap implements IntShortMap { - public final IntShortHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationIntShortHashMap(IntShortHashMap delegate, IntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationIntShortHashMap(IntShortHashMap delegate, IntShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final int[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - int[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, IntShortComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final int[] keys = delegate.keys; - final short[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(int key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(IntContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(IntShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final short[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final int[] keys = delegate.keys; - final short[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public IntCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ShortContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public short get(int key) { - return delegate.get(key); - } - - @Override - public short getOrDefault(int key, short defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public short put(int key, short value) { - throw readOnlyException(); - } - - @Override - public int putAll(IntShortAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public short putOrAdd(int key, short putValue, short incrementValue) { - throw readOnlyException(); - } - - @Override - public short addTo(int key, short additionValue) { - throw readOnlyException(); - } - - @Override - public short remove(int key) { - throw readOnlyException(); - } - - @Override - public int indexOf(int key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public short indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public short indexReplace(int index, short newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, int key, short value) { - throw readOnlyException(); - } - - @Override - public short indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final IntShortCursor cursor = new IntShortCursor(); - private int index; - - @Override - protected IntShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { - private final SortedIterationIntShortHashMap owner = SortedIterationIntShortHashMap.this; - - @Override - public boolean contains(int e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((IntShortProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((IntShortPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractShortCollection { - private final SortedIterationIntShortHashMap owner = SortedIterationIntShortHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(short value) { - for (IntShortCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((IntShortProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((IntShortPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongByteHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationLongByteHashMap.java deleted file mode 100644 index 46b063f7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongByteHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link LongByteHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link LongByteHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationLongByteHashMap implements LongByteMap { - public final LongByteHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationLongByteHashMap(LongByteHashMap delegate, LongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationLongByteHashMap(LongByteHashMap delegate, LongByteComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final long[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - long[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongByteComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final long[] keys = delegate.keys; - final byte[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(long key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(LongContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongBytePredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final byte[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final byte[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public LongCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ByteContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public byte get(long key) { - return delegate.get(key); - } - - @Override - public byte getOrDefault(long key, byte defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public byte put(long key, byte value) { - throw readOnlyException(); - } - - @Override - public int putAll(LongByteAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public byte putOrAdd(long key, byte putValue, byte incrementValue) { - throw readOnlyException(); - } - - @Override - public byte addTo(long key, byte additionValue) { - throw readOnlyException(); - } - - @Override - public byte remove(long key) { - throw readOnlyException(); - } - - @Override - public int indexOf(long key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public byte indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public byte indexReplace(int index, byte newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, long key, byte value) { - throw readOnlyException(); - } - - @Override - public byte indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongByteCursor cursor = new LongByteCursor(); - private int index; - - @Override - protected LongByteCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final SortedIterationLongByteHashMap owner = SortedIterationLongByteHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongByteProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongBytePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractByteCollection { - private final SortedIterationLongByteHashMap owner = SortedIterationLongByteHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(byte value) { - for (LongByteCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((LongByteProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((LongBytePredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final byte e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final BytePredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ByteCursor cursor = new ByteCursor(); - private int index; - - @Override - protected ByteCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongCharHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationLongCharHashMap.java deleted file mode 100644 index c4daf3d0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongCharHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link LongCharHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link LongCharHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationLongCharHashMap implements LongCharMap { - public final LongCharHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationLongCharHashMap(LongCharHashMap delegate, LongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationLongCharHashMap(LongCharHashMap delegate, LongCharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final long[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - long[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongCharComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final long[] keys = delegate.keys; - final char[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(long key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(LongContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongCharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final char[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final char[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public LongCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public CharContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public char get(long key) { - return delegate.get(key); - } - - @Override - public char getOrDefault(long key, char defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public char put(long key, char value) { - throw readOnlyException(); - } - - @Override - public int putAll(LongCharAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public char putOrAdd(long key, char putValue, char incrementValue) { - throw readOnlyException(); - } - - @Override - public char addTo(long key, char additionValue) { - throw readOnlyException(); - } - - @Override - public char remove(long key) { - throw readOnlyException(); - } - - @Override - public int indexOf(long key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public char indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public char indexReplace(int index, char newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, long key, char value) { - throw readOnlyException(); - } - - @Override - public char indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongCharCursor cursor = new LongCharCursor(); - private int index; - - @Override - protected LongCharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final SortedIterationLongCharHashMap owner = SortedIterationLongCharHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongCharProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongCharPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractCharCollection { - private final SortedIterationLongCharHashMap owner = SortedIterationLongCharHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(char value) { - for (LongCharCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((LongCharProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((LongCharPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongDoubleHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationLongDoubleHashMap.java deleted file mode 100644 index bbd41530..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongDoubleHashMap.java +++ /dev/null @@ -1,441 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link LongDoubleHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link LongDoubleHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationLongDoubleHashMap implements LongDoubleMap { - public final LongDoubleHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationLongDoubleHashMap(LongDoubleHashMap delegate, LongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationLongDoubleHashMap( - LongDoubleHashMap delegate, LongDoubleComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final long[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - long[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongDoubleComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final long[] keys = delegate.keys; - final double[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(long key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(LongContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongDoublePredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final double[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final double[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public LongCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public DoubleContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public double get(long key) { - return delegate.get(key); - } - - @Override - public double getOrDefault(long key, double defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public double put(long key, double value) { - throw readOnlyException(); - } - - @Override - public int putAll(LongDoubleAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public double putOrAdd(long key, double putValue, double incrementValue) { - throw readOnlyException(); - } - - @Override - public double addTo(long key, double additionValue) { - throw readOnlyException(); - } - - @Override - public double remove(long key) { - throw readOnlyException(); - } - - @Override - public int indexOf(long key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public double indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public double indexReplace(int index, double newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, long key, double value) { - throw readOnlyException(); - } - - @Override - public double indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongDoubleCursor cursor = new LongDoubleCursor(); - private int index; - - @Override - protected LongDoubleCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final SortedIterationLongDoubleHashMap owner = SortedIterationLongDoubleHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongDoubleProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongDoublePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractDoubleCollection { - private final SortedIterationLongDoubleHashMap owner = SortedIterationLongDoubleHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(double value) { - for (LongDoubleCursor c : owner) { - if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((LongDoubleProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((LongDoublePredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final double e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final DoublePredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final DoubleCursor cursor = new DoubleCursor(); - private int index; - - @Override - protected DoubleCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongFloatHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationLongFloatHashMap.java deleted file mode 100644 index 2a8e61d2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongFloatHashMap.java +++ /dev/null @@ -1,441 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link LongFloatHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link LongFloatHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationLongFloatHashMap implements LongFloatMap { - public final LongFloatHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationLongFloatHashMap(LongFloatHashMap delegate, LongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationLongFloatHashMap( - LongFloatHashMap delegate, LongFloatComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final long[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - long[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongFloatComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final long[] keys = delegate.keys; - final float[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(long key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(LongContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongFloatPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final float[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final float[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public LongCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public FloatContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public float get(long key) { - return delegate.get(key); - } - - @Override - public float getOrDefault(long key, float defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public float put(long key, float value) { - throw readOnlyException(); - } - - @Override - public int putAll(LongFloatAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public float putOrAdd(long key, float putValue, float incrementValue) { - throw readOnlyException(); - } - - @Override - public float addTo(long key, float additionValue) { - throw readOnlyException(); - } - - @Override - public float remove(long key) { - throw readOnlyException(); - } - - @Override - public int indexOf(long key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public float indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public float indexReplace(int index, float newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, long key, float value) { - throw readOnlyException(); - } - - @Override - public float indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongFloatCursor cursor = new LongFloatCursor(); - private int index; - - @Override - protected LongFloatCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final SortedIterationLongFloatHashMap owner = SortedIterationLongFloatHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongFloatProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongFloatPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractFloatCollection { - private final SortedIterationLongFloatHashMap owner = SortedIterationLongFloatHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(float value) { - for (LongFloatCursor c : owner) { - if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((LongFloatProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((LongFloatPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final float e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final FloatPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final FloatCursor cursor = new FloatCursor(); - private int index; - - @Override - protected FloatCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongIntHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationLongIntHashMap.java deleted file mode 100644 index 77620aa9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongIntHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link LongIntHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link LongIntHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationLongIntHashMap implements LongIntMap { - public final LongIntHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationLongIntHashMap(LongIntHashMap delegate, LongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationLongIntHashMap(LongIntHashMap delegate, LongIntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final long[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - long[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongIntComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final long[] keys = delegate.keys; - final int[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(long key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(LongContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongIntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final int[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final int[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public LongCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public IntContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public int get(long key) { - return delegate.get(key); - } - - @Override - public int getOrDefault(long key, int defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public int put(long key, int value) { - throw readOnlyException(); - } - - @Override - public int putAll(LongIntAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public int putOrAdd(long key, int putValue, int incrementValue) { - throw readOnlyException(); - } - - @Override - public int addTo(long key, int additionValue) { - throw readOnlyException(); - } - - @Override - public int remove(long key) { - throw readOnlyException(); - } - - @Override - public int indexOf(long key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public int indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public int indexReplace(int index, int newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, long key, int value) { - throw readOnlyException(); - } - - @Override - public int indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongIntCursor cursor = new LongIntCursor(); - private int index; - - @Override - protected LongIntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final SortedIterationLongIntHashMap owner = SortedIterationLongIntHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongIntProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongIntPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractIntCollection { - private final SortedIterationLongIntHashMap owner = SortedIterationLongIntHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(int value) { - for (LongIntCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((LongIntProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((LongIntPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongLongHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationLongLongHashMap.java deleted file mode 100644 index 605189b3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongLongHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link LongLongHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link LongLongHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationLongLongHashMap implements LongLongMap { - public final LongLongHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationLongLongHashMap(LongLongHashMap delegate, LongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationLongLongHashMap(LongLongHashMap delegate, LongLongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final long[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - long[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongLongComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final long[] keys = delegate.keys; - final long[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(long key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(LongContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongLongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final long[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final long[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public LongCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public LongContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public long get(long key) { - return delegate.get(key); - } - - @Override - public long getOrDefault(long key, long defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public long put(long key, long value) { - throw readOnlyException(); - } - - @Override - public int putAll(LongLongAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public long putOrAdd(long key, long putValue, long incrementValue) { - throw readOnlyException(); - } - - @Override - public long addTo(long key, long additionValue) { - throw readOnlyException(); - } - - @Override - public long remove(long key) { - throw readOnlyException(); - } - - @Override - public int indexOf(long key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public long indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public long indexReplace(int index, long newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, long key, long value) { - throw readOnlyException(); - } - - @Override - public long indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongLongCursor cursor = new LongLongCursor(); - private int index; - - @Override - protected LongLongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final SortedIterationLongLongHashMap owner = SortedIterationLongLongHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongLongProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongLongPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractLongCollection { - private final SortedIterationLongLongHashMap owner = SortedIterationLongLongHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(long value) { - for (LongLongCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((LongLongProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((LongLongPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongObjectHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationLongObjectHashMap.java deleted file mode 100644 index b7f64fe4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongObjectHashMap.java +++ /dev/null @@ -1,435 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link LongObjectHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link LongObjectHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationLongObjectHashMap implements LongObjectMap { - public final LongObjectHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationLongObjectHashMap( - LongObjectHashMap delegate, LongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationLongObjectHashMap( - LongObjectHashMap delegate, LongObjectComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final long[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - long[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongObjectComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final long[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(long key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(LongContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public LongCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ObjectContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public VType get(long key) { - return delegate.get(key); - } - - @Override - public VType getOrDefault(long key, VType defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public VType put(long key, VType value) { - throw readOnlyException(); - } - - @Override - public int putAll(LongObjectAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public VType remove(long key) { - throw readOnlyException(); - } - - @Override - public int indexOf(long key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public VType indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public VType indexReplace(int index, VType newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, long key, VType value) { - throw readOnlyException(); - } - - @Override - public VType indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final LongObjectCursor cursor = new LongObjectCursor(); - private int index; - - @Override - protected LongObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = (VType) delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final SortedIterationLongObjectHashMap owner = - SortedIterationLongObjectHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongObjectProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongObjectPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractObjectCollection { - private final SortedIterationLongObjectHashMap owner = - SortedIterationLongObjectHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(VType value) { - for (LongObjectCursor c : owner) { - if (java.util.Objects.equals(value, c.value)) { - return true; - } - } - return false; - } - - @Override - public > T forEach(T procedure) { - owner.forEach((LongObjectProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public > T forEach(T predicate) { - owner.forEach((LongObjectPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator> iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final VType e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (VType) delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongShortHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationLongShortHashMap.java deleted file mode 100644 index 63de5c26..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationLongShortHashMap.java +++ /dev/null @@ -1,441 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link LongShortHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link LongShortHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationLongShortHashMap implements LongShortMap { - public final LongShortHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationLongShortHashMap(LongShortHashMap delegate, LongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationLongShortHashMap( - LongShortHashMap delegate, LongShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final long[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - long[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, LongShortComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final long[] keys = delegate.keys; - final short[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(long key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(LongContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(LongShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final short[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final long[] keys = delegate.keys; - final short[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public LongCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ShortContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public short get(long key) { - return delegate.get(key); - } - - @Override - public short getOrDefault(long key, short defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public short put(long key, short value) { - throw readOnlyException(); - } - - @Override - public int putAll(LongShortAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public short putOrAdd(long key, short putValue, short incrementValue) { - throw readOnlyException(); - } - - @Override - public short addTo(long key, short additionValue) { - throw readOnlyException(); - } - - @Override - public short remove(long key) { - throw readOnlyException(); - } - - @Override - public int indexOf(long key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public short indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public short indexReplace(int index, short newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, long key, short value) { - throw readOnlyException(); - } - - @Override - public short indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final LongShortCursor cursor = new LongShortCursor(); - private int index; - - @Override - protected LongShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { - private final SortedIterationLongShortHashMap owner = SortedIterationLongShortHashMap.this; - - @Override - public boolean contains(long e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((LongShortProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((LongShortPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractShortCollection { - private final SortedIterationLongShortHashMap owner = SortedIterationLongShortHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(short value) { - for (LongShortCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((LongShortProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((LongShortPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectByteHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectByteHashMap.java deleted file mode 100644 index 011ace2f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectByteHashMap.java +++ /dev/null @@ -1,447 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Comparator; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ObjectByteHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ObjectByteHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationObjectByteHashMap implements ObjectByteMap { - public final ObjectByteHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationObjectByteHashMap( - ObjectByteHashMap delegate, Comparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationObjectByteHashMap( - ObjectByteHashMap delegate, ObjectByteComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final KType[] keys = (KType[]) delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!(((KType) keys[keyIndex]) == null)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - KType[] keys = (KType[]) delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ObjectByteComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final KType[] keys = (KType[]) delegate.keys; - final byte[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(KType key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ObjectContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectBytePredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final byte[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final byte[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ObjectCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ByteContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public byte get(KType key) { - return delegate.get(key); - } - - @Override - public byte getOrDefault(KType key, byte defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public byte put(KType key, byte value) { - throw readOnlyException(); - } - - @Override - public int putAll(ObjectByteAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public byte putOrAdd(KType key, byte putValue, byte incrementValue) { - throw readOnlyException(); - } - - @Override - public byte addTo(KType key, byte additionValue) { - throw readOnlyException(); - } - - @Override - public byte remove(KType key) { - throw readOnlyException(); - } - - @Override - public int indexOf(KType key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public byte indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public byte indexReplace(int index, byte newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, KType key, byte value) { - throw readOnlyException(); - } - - @Override - public byte indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectByteCursor cursor = new ObjectByteCursor(); - private int index; - - @Override - protected ObjectByteCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = (KType) delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final SortedIterationObjectByteHashMap owner = - SortedIterationObjectByteHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectByteProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectBytePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final KType e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (KType) delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractByteCollection { - private final SortedIterationObjectByteHashMap owner = - SortedIterationObjectByteHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(byte value) { - for (ObjectByteCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ObjectByteProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ObjectBytePredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final byte e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final BytePredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ByteCursor cursor = new ByteCursor(); - private int index; - - @Override - protected ByteCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectCharHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectCharHashMap.java deleted file mode 100644 index 37f0f25a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectCharHashMap.java +++ /dev/null @@ -1,447 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Comparator; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ObjectCharHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ObjectCharHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationObjectCharHashMap implements ObjectCharMap { - public final ObjectCharHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationObjectCharHashMap( - ObjectCharHashMap delegate, Comparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationObjectCharHashMap( - ObjectCharHashMap delegate, ObjectCharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final KType[] keys = (KType[]) delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!(((KType) keys[keyIndex]) == null)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - KType[] keys = (KType[]) delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ObjectCharComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final KType[] keys = (KType[]) delegate.keys; - final char[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(KType key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ObjectContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectCharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final char[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final char[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ObjectCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public CharContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public char get(KType key) { - return delegate.get(key); - } - - @Override - public char getOrDefault(KType key, char defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public char put(KType key, char value) { - throw readOnlyException(); - } - - @Override - public int putAll(ObjectCharAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public char putOrAdd(KType key, char putValue, char incrementValue) { - throw readOnlyException(); - } - - @Override - public char addTo(KType key, char additionValue) { - throw readOnlyException(); - } - - @Override - public char remove(KType key) { - throw readOnlyException(); - } - - @Override - public int indexOf(KType key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public char indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public char indexReplace(int index, char newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, KType key, char value) { - throw readOnlyException(); - } - - @Override - public char indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectCharCursor cursor = new ObjectCharCursor(); - private int index; - - @Override - protected ObjectCharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = (KType) delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final SortedIterationObjectCharHashMap owner = - SortedIterationObjectCharHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectCharProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectCharPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final KType e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (KType) delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractCharCollection { - private final SortedIterationObjectCharHashMap owner = - SortedIterationObjectCharHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(char value) { - for (ObjectCharCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ObjectCharProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ObjectCharPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectDoubleHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectDoubleHashMap.java deleted file mode 100644 index f593fe6a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectDoubleHashMap.java +++ /dev/null @@ -1,447 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Comparator; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ObjectDoubleHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ObjectDoubleHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationObjectDoubleHashMap implements ObjectDoubleMap { - public final ObjectDoubleHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationObjectDoubleHashMap( - ObjectDoubleHashMap delegate, Comparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationObjectDoubleHashMap( - ObjectDoubleHashMap delegate, ObjectDoubleComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final KType[] keys = (KType[]) delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!(((KType) keys[keyIndex]) == null)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - KType[] keys = (KType[]) delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ObjectDoubleComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final KType[] keys = (KType[]) delegate.keys; - final double[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(KType key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ObjectContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectDoublePredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final double[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final double[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ObjectCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public DoubleContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public double get(KType key) { - return delegate.get(key); - } - - @Override - public double getOrDefault(KType key, double defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public double put(KType key, double value) { - throw readOnlyException(); - } - - @Override - public int putAll(ObjectDoubleAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public double putOrAdd(KType key, double putValue, double incrementValue) { - throw readOnlyException(); - } - - @Override - public double addTo(KType key, double additionValue) { - throw readOnlyException(); - } - - @Override - public double remove(KType key) { - throw readOnlyException(); - } - - @Override - public int indexOf(KType key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public double indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public double indexReplace(int index, double newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, KType key, double value) { - throw readOnlyException(); - } - - @Override - public double indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectDoubleCursor cursor = new ObjectDoubleCursor(); - private int index; - - @Override - protected ObjectDoubleCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = (KType) delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final SortedIterationObjectDoubleHashMap owner = - SortedIterationObjectDoubleHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectDoubleProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectDoublePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final KType e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (KType) delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractDoubleCollection { - private final SortedIterationObjectDoubleHashMap owner = - SortedIterationObjectDoubleHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(double value) { - for (ObjectDoubleCursor c : owner) { - if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ObjectDoubleProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ObjectDoublePredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final double e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final DoublePredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final DoubleCursor cursor = new DoubleCursor(); - private int index; - - @Override - protected DoubleCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectFloatHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectFloatHashMap.java deleted file mode 100644 index 4781dd42..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectFloatHashMap.java +++ /dev/null @@ -1,447 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Comparator; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ObjectFloatHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ObjectFloatHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationObjectFloatHashMap implements ObjectFloatMap { - public final ObjectFloatHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationObjectFloatHashMap( - ObjectFloatHashMap delegate, Comparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationObjectFloatHashMap( - ObjectFloatHashMap delegate, ObjectFloatComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final KType[] keys = (KType[]) delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!(((KType) keys[keyIndex]) == null)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - KType[] keys = (KType[]) delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ObjectFloatComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final KType[] keys = (KType[]) delegate.keys; - final float[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(KType key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ObjectContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectFloatPredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final float[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final float[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ObjectCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public FloatContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public float get(KType key) { - return delegate.get(key); - } - - @Override - public float getOrDefault(KType key, float defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public float put(KType key, float value) { - throw readOnlyException(); - } - - @Override - public int putAll(ObjectFloatAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public float putOrAdd(KType key, float putValue, float incrementValue) { - throw readOnlyException(); - } - - @Override - public float addTo(KType key, float additionValue) { - throw readOnlyException(); - } - - @Override - public float remove(KType key) { - throw readOnlyException(); - } - - @Override - public int indexOf(KType key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public float indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public float indexReplace(int index, float newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, KType key, float value) { - throw readOnlyException(); - } - - @Override - public float indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectFloatCursor cursor = new ObjectFloatCursor(); - private int index; - - @Override - protected ObjectFloatCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = (KType) delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final SortedIterationObjectFloatHashMap owner = - SortedIterationObjectFloatHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectFloatProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectFloatPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final KType e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (KType) delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractFloatCollection { - private final SortedIterationObjectFloatHashMap owner = - SortedIterationObjectFloatHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(float value) { - for (ObjectFloatCursor c : owner) { - if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ObjectFloatProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ObjectFloatPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final float e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final FloatPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final FloatCursor cursor = new FloatCursor(); - private int index; - - @Override - protected FloatCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectIntHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectIntHashMap.java deleted file mode 100644 index 84b1aad2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectIntHashMap.java +++ /dev/null @@ -1,447 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Comparator; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ObjectIntHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ObjectIntHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationObjectIntHashMap implements ObjectIntMap { - public final ObjectIntHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationObjectIntHashMap( - ObjectIntHashMap delegate, Comparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationObjectIntHashMap( - ObjectIntHashMap delegate, ObjectIntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final KType[] keys = (KType[]) delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!(((KType) keys[keyIndex]) == null)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - KType[] keys = (KType[]) delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ObjectIntComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final KType[] keys = (KType[]) delegate.keys; - final int[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(KType key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ObjectContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectIntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final int[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final int[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ObjectCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public IntContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public int get(KType key) { - return delegate.get(key); - } - - @Override - public int getOrDefault(KType key, int defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public int put(KType key, int value) { - throw readOnlyException(); - } - - @Override - public int putAll(ObjectIntAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public int putOrAdd(KType key, int putValue, int incrementValue) { - throw readOnlyException(); - } - - @Override - public int addTo(KType key, int additionValue) { - throw readOnlyException(); - } - - @Override - public int remove(KType key) { - throw readOnlyException(); - } - - @Override - public int indexOf(KType key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public int indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public int indexReplace(int index, int newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, KType key, int value) { - throw readOnlyException(); - } - - @Override - public int indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectIntCursor cursor = new ObjectIntCursor(); - private int index; - - @Override - protected ObjectIntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = (KType) delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final SortedIterationObjectIntHashMap owner = - SortedIterationObjectIntHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectIntProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectIntPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final KType e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (KType) delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractIntCollection { - private final SortedIterationObjectIntHashMap owner = - SortedIterationObjectIntHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(int value) { - for (ObjectIntCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ObjectIntProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ObjectIntPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectLongHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectLongHashMap.java deleted file mode 100644 index f353773c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectLongHashMap.java +++ /dev/null @@ -1,447 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Comparator; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ObjectLongHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ObjectLongHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationObjectLongHashMap implements ObjectLongMap { - public final ObjectLongHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationObjectLongHashMap( - ObjectLongHashMap delegate, Comparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationObjectLongHashMap( - ObjectLongHashMap delegate, ObjectLongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final KType[] keys = (KType[]) delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!(((KType) keys[keyIndex]) == null)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - KType[] keys = (KType[]) delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ObjectLongComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final KType[] keys = (KType[]) delegate.keys; - final long[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(KType key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ObjectContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectLongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final long[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final long[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ObjectCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public LongContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public long get(KType key) { - return delegate.get(key); - } - - @Override - public long getOrDefault(KType key, long defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public long put(KType key, long value) { - throw readOnlyException(); - } - - @Override - public int putAll(ObjectLongAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public long putOrAdd(KType key, long putValue, long incrementValue) { - throw readOnlyException(); - } - - @Override - public long addTo(KType key, long additionValue) { - throw readOnlyException(); - } - - @Override - public long remove(KType key) { - throw readOnlyException(); - } - - @Override - public int indexOf(KType key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public long indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public long indexReplace(int index, long newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, KType key, long value) { - throw readOnlyException(); - } - - @Override - public long indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectLongCursor cursor = new ObjectLongCursor(); - private int index; - - @Override - protected ObjectLongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = (KType) delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final SortedIterationObjectLongHashMap owner = - SortedIterationObjectLongHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectLongProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectLongPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final KType e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (KType) delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractLongCollection { - private final SortedIterationObjectLongHashMap owner = - SortedIterationObjectLongHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(long value) { - for (ObjectLongCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ObjectLongProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ObjectLongPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectObjectHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectObjectHashMap.java deleted file mode 100644 index d1c881be..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectObjectHashMap.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Comparator; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ObjectObjectHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ObjectObjectHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationObjectObjectHashMap - implements ObjectObjectMap { - public final ObjectObjectHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationObjectObjectHashMap( - ObjectObjectHashMap delegate, Comparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationObjectObjectHashMap( - ObjectObjectHashMap delegate, ObjectObjectComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final KType[] keys = (KType[]) delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!(((KType) keys[keyIndex]) == null)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - KType[] keys = (KType[]) delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder( - int[] entryIndexes, ObjectObjectComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final KType[] keys = (KType[]) delegate.keys; - final VType[] values = (VType[]) delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(KType key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ObjectContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final VType[] values = (VType[]) delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final VType[] values = (VType[]) delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ObjectCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ObjectContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public VType get(KType key) { - return delegate.get(key); - } - - @Override - public VType getOrDefault(KType key, VType defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public VType put(KType key, VType value) { - throw readOnlyException(); - } - - @Override - public int putAll(ObjectObjectAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll( - Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public VType remove(KType key) { - throw readOnlyException(); - } - - @Override - public int indexOf(KType key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public VType indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public VType indexReplace(int index, VType newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, KType key, VType value) { - throw readOnlyException(); - } - - @Override - public VType indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectObjectCursor cursor = new ObjectObjectCursor(); - private int index; - - @Override - protected ObjectObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = (KType) delegate.keys[slot]; - cursor.value = (VType) delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final SortedIterationObjectObjectHashMap owner = - SortedIterationObjectObjectHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectObjectProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectObjectPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final KType e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (KType) delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractObjectCollection { - private final SortedIterationObjectObjectHashMap owner = - SortedIterationObjectObjectHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(VType value) { - for (ObjectObjectCursor c : owner) { - if (java.util.Objects.equals(value, c.value)) { - return true; - } - } - return false; - } - - @Override - public > T forEach(T procedure) { - owner.forEach((ObjectObjectProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public > T forEach(T predicate) { - owner.forEach((ObjectObjectPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator> iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final VType e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (VType) delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectShortHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectShortHashMap.java deleted file mode 100644 index 69e7bd7e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationObjectShortHashMap.java +++ /dev/null @@ -1,447 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Comparator; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ObjectShortHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ObjectShortHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationObjectShortHashMap implements ObjectShortMap { - public final ObjectShortHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationObjectShortHashMap( - ObjectShortHashMap delegate, Comparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationObjectShortHashMap( - ObjectShortHashMap delegate, ObjectShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final KType[] keys = (KType[]) delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!(((KType) keys[keyIndex]) == null)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - KType[] keys = (KType[]) delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ObjectShortComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final KType[] keys = (KType[]) delegate.keys; - final short[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(KType key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ObjectContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final short[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final KType[] keys = (KType[]) delegate.keys; - final short[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ObjectCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ShortContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public short get(KType key) { - return delegate.get(key); - } - - @Override - public short getOrDefault(KType key, short defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public short put(KType key, short value) { - throw readOnlyException(); - } - - @Override - public int putAll(ObjectShortAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public short putOrAdd(KType key, short putValue, short incrementValue) { - throw readOnlyException(); - } - - @Override - public short addTo(KType key, short additionValue) { - throw readOnlyException(); - } - - @Override - public short remove(KType key) { - throw readOnlyException(); - } - - @Override - public int indexOf(KType key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public short indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public short indexReplace(int index, short newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, KType key, short value) { - throw readOnlyException(); - } - - @Override - public short indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ObjectShortCursor cursor = new ObjectShortCursor(); - private int index; - - @Override - protected ObjectShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = (KType) delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractObjectCollection - implements ObjectLookupContainer { - private final SortedIterationObjectShortHashMap owner = - SortedIterationObjectShortHashMap.this; - - @Override - public boolean contains(KType e) { - return owner.containsKey(e); - } - - @Override - public > T forEach(final T procedure) { - owner.forEach((ObjectShortProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public > T forEach(final T predicate) { - owner.forEach((ObjectShortPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator> iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final KType e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (KType) delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractShortCollection { - private final SortedIterationObjectShortHashMap owner = - SortedIterationObjectShortHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(short value) { - for (ObjectShortCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ObjectShortProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ObjectShortPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortByteHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationShortByteHashMap.java deleted file mode 100644 index 478d3dec..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortByteHashMap.java +++ /dev/null @@ -1,442 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ShortByteHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ShortByteHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationShortByteHashMap implements ShortByteMap { - public final ShortByteHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationShortByteHashMap(ShortByteHashMap delegate, ShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationShortByteHashMap( - ShortByteHashMap delegate, ShortByteComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final short[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - short[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortByteComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final short[] keys = delegate.keys; - final byte[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(short key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ShortContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortBytePredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final byte[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final byte[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ShortCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ByteContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public byte get(short key) { - return delegate.get(key); - } - - @Override - public byte getOrDefault(short key, byte defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public byte put(short key, byte value) { - throw readOnlyException(); - } - - @Override - public int putAll(ShortByteAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public byte putOrAdd(short key, byte putValue, byte incrementValue) { - throw readOnlyException(); - } - - @Override - public byte addTo(short key, byte additionValue) { - throw readOnlyException(); - } - - @Override - public byte remove(short key) { - throw readOnlyException(); - } - - @Override - public int indexOf(short key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public byte indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public byte indexReplace(int index, byte newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, short key, byte value) { - throw readOnlyException(); - } - - @Override - public byte indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortByteCursor cursor = new ShortByteCursor(); - private int index; - - @Override - protected ShortByteCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractShortCollection - implements ShortLookupContainer { - private final SortedIterationShortByteHashMap owner = SortedIterationShortByteHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortByteProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortBytePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractByteCollection { - private final SortedIterationShortByteHashMap owner = SortedIterationShortByteHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(byte value) { - for (ShortByteCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ShortByteProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ShortBytePredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final byte e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final BytePredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ByteCursor cursor = new ByteCursor(); - private int index; - - @Override - protected ByteCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortCharHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationShortCharHashMap.java deleted file mode 100644 index 3f4ad7df..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortCharHashMap.java +++ /dev/null @@ -1,442 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ShortCharHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ShortCharHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationShortCharHashMap implements ShortCharMap { - public final ShortCharHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationShortCharHashMap(ShortCharHashMap delegate, ShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationShortCharHashMap( - ShortCharHashMap delegate, ShortCharComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final short[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - short[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortCharComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final short[] keys = delegate.keys; - final char[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(short key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ShortContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortCharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final char[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final char[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ShortCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public CharContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public char get(short key) { - return delegate.get(key); - } - - @Override - public char getOrDefault(short key, char defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public char put(short key, char value) { - throw readOnlyException(); - } - - @Override - public int putAll(ShortCharAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public char putOrAdd(short key, char putValue, char incrementValue) { - throw readOnlyException(); - } - - @Override - public char addTo(short key, char additionValue) { - throw readOnlyException(); - } - - @Override - public char remove(short key) { - throw readOnlyException(); - } - - @Override - public int indexOf(short key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public char indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public char indexReplace(int index, char newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, short key, char value) { - throw readOnlyException(); - } - - @Override - public char indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortCharCursor cursor = new ShortCharCursor(); - private int index; - - @Override - protected ShortCharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractShortCollection - implements ShortLookupContainer { - private final SortedIterationShortCharHashMap owner = SortedIterationShortCharHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortCharProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortCharPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractCharCollection { - private final SortedIterationShortCharHashMap owner = SortedIterationShortCharHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(char value) { - for (ShortCharCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ShortCharProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ShortCharPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final char e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final CharPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final CharCursor cursor = new CharCursor(); - private int index; - - @Override - protected CharCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortDoubleHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationShortDoubleHashMap.java deleted file mode 100644 index a9ae3265..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortDoubleHashMap.java +++ /dev/null @@ -1,443 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ShortDoubleHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ShortDoubleHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationShortDoubleHashMap implements ShortDoubleMap { - public final ShortDoubleHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationShortDoubleHashMap( - ShortDoubleHashMap delegate, ShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationShortDoubleHashMap( - ShortDoubleHashMap delegate, ShortDoubleComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final short[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - short[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortDoubleComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final short[] keys = delegate.keys; - final double[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(short key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ShortContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortDoublePredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final double[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final double[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ShortCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public DoubleContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public double get(short key) { - return delegate.get(key); - } - - @Override - public double getOrDefault(short key, double defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public double put(short key, double value) { - throw readOnlyException(); - } - - @Override - public int putAll(ShortDoubleAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public double putOrAdd(short key, double putValue, double incrementValue) { - throw readOnlyException(); - } - - @Override - public double addTo(short key, double additionValue) { - throw readOnlyException(); - } - - @Override - public double remove(short key) { - throw readOnlyException(); - } - - @Override - public int indexOf(short key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public double indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public double indexReplace(int index, double newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, short key, double value) { - throw readOnlyException(); - } - - @Override - public double indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortDoubleCursor cursor = new ShortDoubleCursor(); - private int index; - - @Override - protected ShortDoubleCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractShortCollection - implements ShortLookupContainer { - private final SortedIterationShortDoubleHashMap owner = SortedIterationShortDoubleHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortDoubleProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortDoublePredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractDoubleCollection { - private final SortedIterationShortDoubleHashMap owner = SortedIterationShortDoubleHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(double value) { - for (ShortDoubleCursor c : owner) { - if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ShortDoubleProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ShortDoublePredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final double e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final DoublePredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final DoubleCursor cursor = new DoubleCursor(); - private int index; - - @Override - protected DoubleCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortFloatHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationShortFloatHashMap.java deleted file mode 100644 index bad3ad03..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortFloatHashMap.java +++ /dev/null @@ -1,442 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ShortFloatHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ShortFloatHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationShortFloatHashMap implements ShortFloatMap { - public final ShortFloatHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationShortFloatHashMap(ShortFloatHashMap delegate, ShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationShortFloatHashMap( - ShortFloatHashMap delegate, ShortFloatComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final short[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - short[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortFloatComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final short[] keys = delegate.keys; - final float[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(short key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ShortContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortFloatPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final float[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final float[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ShortCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public FloatContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public float get(short key) { - return delegate.get(key); - } - - @Override - public float getOrDefault(short key, float defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public float put(short key, float value) { - throw readOnlyException(); - } - - @Override - public int putAll(ShortFloatAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public float putOrAdd(short key, float putValue, float incrementValue) { - throw readOnlyException(); - } - - @Override - public float addTo(short key, float additionValue) { - throw readOnlyException(); - } - - @Override - public float remove(short key) { - throw readOnlyException(); - } - - @Override - public int indexOf(short key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public float indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public float indexReplace(int index, float newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, short key, float value) { - throw readOnlyException(); - } - - @Override - public float indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortFloatCursor cursor = new ShortFloatCursor(); - private int index; - - @Override - protected ShortFloatCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractShortCollection - implements ShortLookupContainer { - private final SortedIterationShortFloatHashMap owner = SortedIterationShortFloatHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortFloatProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortFloatPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractFloatCollection { - private final SortedIterationShortFloatHashMap owner = SortedIterationShortFloatHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(float value) { - for (ShortFloatCursor c : owner) { - if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ShortFloatProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ShortFloatPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final float e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final FloatPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final FloatCursor cursor = new FloatCursor(); - private int index; - - @Override - protected FloatCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortIntHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationShortIntHashMap.java deleted file mode 100644 index 501b0a07..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortIntHashMap.java +++ /dev/null @@ -1,441 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ShortIntHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ShortIntHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationShortIntHashMap implements ShortIntMap { - public final ShortIntHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationShortIntHashMap(ShortIntHashMap delegate, ShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationShortIntHashMap(ShortIntHashMap delegate, ShortIntComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final short[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - short[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortIntComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final short[] keys = delegate.keys; - final int[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(short key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ShortContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortIntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final int[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final int[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ShortCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public IntContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public int get(short key) { - return delegate.get(key); - } - - @Override - public int getOrDefault(short key, int defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public int put(short key, int value) { - throw readOnlyException(); - } - - @Override - public int putAll(ShortIntAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public int putOrAdd(short key, int putValue, int incrementValue) { - throw readOnlyException(); - } - - @Override - public int addTo(short key, int additionValue) { - throw readOnlyException(); - } - - @Override - public int remove(short key) { - throw readOnlyException(); - } - - @Override - public int indexOf(short key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public int indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public int indexReplace(int index, int newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, short key, int value) { - throw readOnlyException(); - } - - @Override - public int indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortIntCursor cursor = new ShortIntCursor(); - private int index; - - @Override - protected ShortIntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractShortCollection - implements ShortLookupContainer { - private final SortedIterationShortIntHashMap owner = SortedIterationShortIntHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortIntProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortIntPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractIntCollection { - private final SortedIterationShortIntHashMap owner = SortedIterationShortIntHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(int value) { - for (ShortIntCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ShortIntProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ShortIntPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final int e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final IntPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final IntCursor cursor = new IntCursor(); - private int index; - - @Override - protected IntCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortLongHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationShortLongHashMap.java deleted file mode 100644 index 5aae2e1f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortLongHashMap.java +++ /dev/null @@ -1,442 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ShortLongHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ShortLongHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationShortLongHashMap implements ShortLongMap { - public final ShortLongHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationShortLongHashMap(ShortLongHashMap delegate, ShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationShortLongHashMap( - ShortLongHashMap delegate, ShortLongComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final short[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - short[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortLongComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final short[] keys = delegate.keys; - final long[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(short key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ShortContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortLongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final long[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final long[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ShortCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public LongContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public long get(short key) { - return delegate.get(key); - } - - @Override - public long getOrDefault(short key, long defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public long put(short key, long value) { - throw readOnlyException(); - } - - @Override - public int putAll(ShortLongAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public long putOrAdd(short key, long putValue, long incrementValue) { - throw readOnlyException(); - } - - @Override - public long addTo(short key, long additionValue) { - throw readOnlyException(); - } - - @Override - public long remove(short key) { - throw readOnlyException(); - } - - @Override - public int indexOf(short key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public long indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public long indexReplace(int index, long newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, short key, long value) { - throw readOnlyException(); - } - - @Override - public long indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortLongCursor cursor = new ShortLongCursor(); - private int index; - - @Override - protected ShortLongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractShortCollection - implements ShortLookupContainer { - private final SortedIterationShortLongHashMap owner = SortedIterationShortLongHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortLongProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortLongPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractLongCollection { - private final SortedIterationShortLongHashMap owner = SortedIterationShortLongHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(long value) { - for (ShortLongCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ShortLongProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ShortLongPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final long e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final LongPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final LongCursor cursor = new LongCursor(); - private int index; - - @Override - protected LongCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortObjectHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationShortObjectHashMap.java deleted file mode 100644 index 989690ae..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortObjectHashMap.java +++ /dev/null @@ -1,436 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ShortObjectHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ShortObjectHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@SuppressWarnings("unchecked") -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationShortObjectHashMap implements ShortObjectMap { - public final ShortObjectHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationShortObjectHashMap( - ShortObjectHashMap delegate, ShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationShortObjectHashMap( - ShortObjectHashMap delegate, ShortObjectComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final short[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - short[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortObjectComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final short[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator> iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(short key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ShortContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public > T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public > T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final VType[] values = (VType[]) delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ShortCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ObjectContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public VType get(short key) { - return delegate.get(key); - } - - @Override - public VType getOrDefault(short key, VType defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public VType put(short key, VType value) { - throw readOnlyException(); - } - - @Override - public int putAll(ShortObjectAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable> iterable) { - throw readOnlyException(); - } - - @Override - public VType remove(short key) { - throw readOnlyException(); - } - - @Override - public int indexOf(short key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public VType indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public VType indexReplace(int index, VType newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, short key, VType value) { - throw readOnlyException(); - } - - @Override - public VType indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator> { - private final ShortObjectCursor cursor = new ShortObjectCursor(); - private int index; - - @Override - protected ShortObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = (VType) delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractShortCollection - implements ShortLookupContainer { - private final SortedIterationShortObjectHashMap owner = - SortedIterationShortObjectHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortObjectProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortObjectPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractObjectCollection { - private final SortedIterationShortObjectHashMap owner = - SortedIterationShortObjectHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(VType value) { - for (ShortObjectCursor c : owner) { - if (java.util.Objects.equals(value, c.value)) { - return true; - } - } - return false; - } - - @Override - public > T forEach(T procedure) { - owner.forEach((ShortObjectProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public > T forEach(T predicate) { - owner.forEach((ShortObjectPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator> iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final VType e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final ObjectPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator> { - private final ObjectCursor cursor = new ObjectCursor(); - private int index; - - @Override - protected ObjectCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = (VType) delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortShortHashMap.java b/sources/main/java/com/carrotsearch/hppc/SortedIterationShortShortHashMap.java deleted file mode 100644 index d7266230..00000000 --- a/sources/main/java/com/carrotsearch/hppc/SortedIterationShortShortHashMap.java +++ /dev/null @@ -1,442 +0,0 @@ -package com.carrotsearch.hppc; - -import com.carrotsearch.hppc.comparators.*; -import com.carrotsearch.hppc.cursors.*; -import com.carrotsearch.hppc.predicates.*; -import com.carrotsearch.hppc.procedures.*; -import com.carrotsearch.hppc.sorting.QuickSort; -import java.util.Iterator; -import java.util.function.IntBinaryOperator; - -/** - * Read-only view with sorted iteration order on a delegate {@link ShortShortHashMap}. - * - *

In its constructor, this view creates its own iteration order array and sorts it, which is in - * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same - * performance as the delegate map. - * - *

This view is read-only. In addition, the delegate map must not be modified while the view is - * used, otherwise the iteration is undefined. - * - *

Since this view provides a fixed iteration order, it must not be used to add entries to - * another {@link ShortShortHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. - */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "SortedIterationKTypeVTypeHashMap.java") -public class SortedIterationShortShortHashMap implements ShortShortMap { - public final ShortShortHashMap delegate; - public final int[] iterationOrder; - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on the keys. - */ - public SortedIterationShortShortHashMap(ShortShortHashMap delegate, ShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - /** - * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is - * based on the provided comparator on keys and values. - */ - public SortedIterationShortShortHashMap( - ShortShortHashMap delegate, ShortShortComparator comparator) { - this.delegate = delegate; - this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); - } - - private int[] createEntryIndexes() { - final short[] keys = delegate.keys; - final int size = delegate.size(); - int[] entryIndexes = new int[size]; - int entry = 0; - if (delegate.hasEmptyKey) { - entryIndexes[entry++] = delegate.mask + 1; - } - for (int keyIndex = 0; entry < size; keyIndex++) { - if (!((keys[keyIndex]) == 0)) { - entryIndexes[entry++] = keyIndex; - } - } - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on the keys. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { - QuickSort.sort( - entryIndexes, - (i, j) -> { - short[] keys = delegate.keys; - return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); - }); - return entryIndexes; - } - - /** Sort the iteration order array based on the provided comparator on keys and values. */ - protected int[] sortIterationOrder(int[] entryIndexes, ShortShortComparator comparator) { - QuickSort.sort( - entryIndexes, - new IntBinaryOperator() { - final short[] keys = delegate.keys; - final short[] values = delegate.values; - - @Override - public int applyAsInt(int i, int j) { - int index1 = entryIndexes[i]; - int index2 = entryIndexes[j]; - return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); - } - }); - return entryIndexes; - } - - @Override - public Iterator iterator() { - assert checkUnmodified(); - return new EntryIterator(); - } - - @Override - public boolean containsKey(short key) { - return delegate.containsKey(key); - } - - @Override - public int size() { - assert checkUnmodified(); - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public int removeAll(ShortContainer container) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public T forEach(T procedure) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final short[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - procedure.apply(keys[slot], values[slot]); - } - return procedure; - } - - @Override - public T forEach(T predicate) { - assert checkUnmodified(); - final int[] iterationOrder = this.iterationOrder; - final short[] keys = delegate.keys; - final short[] values = delegate.values; - for (int i = 0, size = size(); i < size; i++) { - int slot = iterationOrder[i]; - if (!predicate.apply(keys[slot], values[slot])) { - break; - } - } - return predicate; - } - - @Override - public ShortCollection keys() { - assert checkUnmodified(); - return new KeysContainer(); - } - - @Override - public ShortContainer values() { - assert checkUnmodified(); - return new ValuesContainer(); - } - - @Override - public short get(short key) { - return delegate.get(key); - } - - @Override - public short getOrDefault(short key, short defaultValue) { - return delegate.getOrDefault(key, defaultValue); - } - - @Override - public short put(short key, short value) { - throw readOnlyException(); - } - - @Override - public int putAll(ShortShortAssociativeContainer container) { - throw readOnlyException(); - } - - @Override - public int putAll(Iterable iterable) { - throw readOnlyException(); - } - - @Override - public short putOrAdd(short key, short putValue, short incrementValue) { - throw readOnlyException(); - } - - @Override - public short addTo(short key, short additionValue) { - throw readOnlyException(); - } - - @Override - public short remove(short key) { - throw readOnlyException(); - } - - @Override - public int indexOf(short key) { - return delegate.indexOf(key); - } - - @Override - public boolean indexExists(int index) { - return delegate.indexExists(index); - } - - @Override - public short indexGet(int index) { - return delegate.indexGet(index); - } - - @Override - public short indexReplace(int index, short newValue) { - throw readOnlyException(); - } - - @Override - public void indexInsert(int index, short key, short value) { - throw readOnlyException(); - } - - @Override - public short indexRemove(int index) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public String visualizeKeyDistribution(int characters) { - return delegate.visualizeKeyDistribution(characters); - } - - private static RuntimeException readOnlyException() { - throw new UnsupportedOperationException("Read-only view cannot be modified"); - } - - private boolean checkUnmodified() { - // Cheap size comparison. - // We could also check the hashcode, but this is heavy for a frequent check. - assert delegate.size() == iterationOrder.length - : "The delegate map changed; this is not supported by this read-only view"; - return true; - } - - /** An iterator implementation for {@link #iterator}. */ - private final class EntryIterator extends AbstractIterator { - private final ShortShortCursor cursor = new ShortShortCursor(); - private int index; - - @Override - protected ShortShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.key = delegate.keys[slot]; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the keys in sorted order. */ - private final class KeysContainer extends AbstractShortCollection - implements ShortLookupContainer { - private final SortedIterationShortShortHashMap owner = SortedIterationShortShortHashMap.this; - - @Override - public boolean contains(short e) { - return owner.containsKey(e); - } - - @Override - public T forEach(final T procedure) { - owner.forEach((ShortShortProcedure) (k, v) -> procedure.apply(k)); - return procedure; - } - - @Override - public T forEach(final T predicate) { - owner.forEach((ShortShortPredicate) (key, value) -> predicate.apply(key)); - return predicate; - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public Iterator iterator() { - return new KeysIterator(); - } - - @Override - public int size() { - return owner.size(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - - @Override - public int removeAll(ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned keys. */ - private final class KeysIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.keys[slot]; - return cursor; - } - return done(); - } - } - - /** A view of the values in sorted order. */ - private final class ValuesContainer extends AbstractShortCollection { - private final SortedIterationShortShortHashMap owner = SortedIterationShortShortHashMap.this; - - @Override - public int size() { - return owner.size(); - } - - @Override - public boolean isEmpty() { - return owner.isEmpty(); - } - - @Override - public boolean contains(short value) { - for (ShortShortCursor c : owner) { - if (((value) == (c.value))) { - return true; - } - } - return false; - } - - @Override - public T forEach(T procedure) { - owner.forEach((ShortShortProcedure) (k, v) -> procedure.apply(v)); - return procedure; - } - - @Override - public T forEach(T predicate) { - owner.forEach((ShortShortPredicate) (k, v) -> predicate.apply(v)); - return predicate; - } - - @Override - public Iterator iterator() { - return new ValuesIterator(); - } - - @Override - public int removeAll(final short e) { - throw readOnlyException(); - } - - @Override - public int removeAll(final ShortPredicate predicate) { - throw readOnlyException(); - } - - @Override - public void clear() { - throw readOnlyException(); - } - - @Override - public void release() { - throw readOnlyException(); - } - } - - /** A sorted iterator over the set of assigned values. */ - private final class ValuesIterator extends AbstractIterator { - private final ShortCursor cursor = new ShortCursor(); - private int index; - - @Override - protected ShortCursor fetch() { - if (index < iterationOrder.length) { - int slot = iterationOrder[index++]; - cursor.index = slot; - cursor.value = delegate.values[slot]; - return cursor; - } - return done(); - } - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/XorShift128P.java b/sources/main/java/com/carrotsearch/hppc/XorShift128P.java deleted file mode 100644 index e9db0a0d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/XorShift128P.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc; - -import java.util.Random; - -/** - * A fast pseudo-random number generator. For simplicity, we do not implement all of {@link Random} - * methods. - * - * @see "https://xorshift.di.unimi.it/" - * @see "https://xorshift.di.unimi.it/xorshift128plus.c" - */ -public class XorShift128P { - /* - * 128 bits of state. - */ - private long state0, state1; - - public XorShift128P(long seed) { - state0 = notZero(BitMixer.mix64(seed)); - state1 = notZero(BitMixer.mix64(seed + 1)); - } - - public XorShift128P() { - this(Containers.randomSeed64()); - } - - public long nextLong() { - long s1 = state0; - long s0 = state1; - state0 = s0; - s1 ^= s1 << 23; - return (state1 = (s1 ^ s0 ^ (s1 >>> 17) ^ (s0 >>> 26))) + s0; - } - - public int nextInt() { - return (int) nextLong(); - } - - private static long notZero(long value) { - return value == 0 ? 0xdeadbeefbabeL : value; - } - - public int nextInt(int bound) { - if (bound <= 0) { - throw new IllegalArgumentException(); - } - - int r = (nextInt() >>> 1); - int m = bound - 1; - if ((bound & m) == 0) { - r = (int) ((bound * (long) r) >> 31); - } else { - for (int u = r; u - (r = u % bound) + m < 0; u = nextInt() >>> 1) {} - } - - return r; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ByteByteComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ByteByteComparator.java deleted file mode 100644 index 734e028b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ByteByteComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two byte, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ByteByteComparator { - int compare(byte k1, byte v1, byte k2, byte v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ByteCharComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ByteCharComparator.java deleted file mode 100644 index 6682edd4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ByteCharComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two byte, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ByteCharComparator { - int compare(byte k1, char v1, byte k2, char v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ByteComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ByteComparator.java deleted file mode 100644 index 0ff9f381..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ByteComparator.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two byte values. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") -public interface ByteComparator { - int compare(byte a, byte b); - - static ByteComparator naturalOrder() { - return Byte::compare; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ByteDoubleComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ByteDoubleComparator.java deleted file mode 100644 index 84b6105f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ByteDoubleComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two byte, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ByteDoubleComparator { - int compare(byte k1, double v1, byte k2, double v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ByteFloatComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ByteFloatComparator.java deleted file mode 100644 index a54901d6..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ByteFloatComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two byte, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ByteFloatComparator { - int compare(byte k1, float v1, byte k2, float v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ByteIntComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ByteIntComparator.java deleted file mode 100644 index e2fed664..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ByteIntComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two byte, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ByteIntComparator { - int compare(byte k1, int v1, byte k2, int v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ByteLongComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ByteLongComparator.java deleted file mode 100644 index 5684a8bc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ByteLongComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two byte, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ByteLongComparator { - int compare(byte k1, long v1, byte k2, long v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ByteObjectComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ByteObjectComparator.java deleted file mode 100644 index fc1c19a8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ByteObjectComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two byte, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ByteObjectComparator { - int compare(byte k1, VType v1, byte k2, VType v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ByteShortComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ByteShortComparator.java deleted file mode 100644 index 154a2167..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ByteShortComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two byte, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ByteShortComparator { - int compare(byte k1, short v1, byte k2, short v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/CharByteComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/CharByteComparator.java deleted file mode 100644 index 807f0e0c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/CharByteComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two char, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface CharByteComparator { - int compare(char k1, byte v1, char k2, byte v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/CharCharComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/CharCharComparator.java deleted file mode 100644 index 0f790620..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/CharCharComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two char, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface CharCharComparator { - int compare(char k1, char v1, char k2, char v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/CharComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/CharComparator.java deleted file mode 100644 index acedac68..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/CharComparator.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two char values. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") -public interface CharComparator { - int compare(char a, char b); - - static CharComparator naturalOrder() { - return Character::compare; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/CharDoubleComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/CharDoubleComparator.java deleted file mode 100644 index 486620ca..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/CharDoubleComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two char, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface CharDoubleComparator { - int compare(char k1, double v1, char k2, double v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/CharFloatComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/CharFloatComparator.java deleted file mode 100644 index 47bc5950..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/CharFloatComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two char, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface CharFloatComparator { - int compare(char k1, float v1, char k2, float v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/CharIntComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/CharIntComparator.java deleted file mode 100644 index c2a225d4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/CharIntComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two char, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface CharIntComparator { - int compare(char k1, int v1, char k2, int v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/CharLongComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/CharLongComparator.java deleted file mode 100644 index 390998ec..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/CharLongComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two char, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface CharLongComparator { - int compare(char k1, long v1, char k2, long v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/CharObjectComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/CharObjectComparator.java deleted file mode 100644 index fdab147d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/CharObjectComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two char, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface CharObjectComparator { - int compare(char k1, VType v1, char k2, VType v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/CharShortComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/CharShortComparator.java deleted file mode 100644 index 91ba9976..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/CharShortComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two char, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface CharShortComparator { - int compare(char k1, short v1, char k2, short v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleByteComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/DoubleByteComparator.java deleted file mode 100644 index 60fae03f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleByteComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two double, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface DoubleByteComparator { - int compare(double k1, byte v1, double k2, byte v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleCharComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/DoubleCharComparator.java deleted file mode 100644 index ec215c93..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleCharComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two double, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface DoubleCharComparator { - int compare(double k1, char v1, double k2, char v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/DoubleComparator.java deleted file mode 100644 index 193b5f90..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleComparator.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two double values. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") -public interface DoubleComparator { - int compare(double a, double b); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleDoubleComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/DoubleDoubleComparator.java deleted file mode 100644 index 20ba2dcc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleDoubleComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two double, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface DoubleDoubleComparator { - int compare(double k1, double v1, double k2, double v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleFloatComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/DoubleFloatComparator.java deleted file mode 100644 index 50aca950..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleFloatComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two double, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface DoubleFloatComparator { - int compare(double k1, float v1, double k2, float v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleIntComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/DoubleIntComparator.java deleted file mode 100644 index afd12514..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleIntComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two double, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface DoubleIntComparator { - int compare(double k1, int v1, double k2, int v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleLongComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/DoubleLongComparator.java deleted file mode 100644 index a843ec6a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleLongComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two double, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface DoubleLongComparator { - int compare(double k1, long v1, double k2, long v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleObjectComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/DoubleObjectComparator.java deleted file mode 100644 index 9d654aab..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleObjectComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two double, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface DoubleObjectComparator { - int compare(double k1, VType v1, double k2, VType v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleShortComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/DoubleShortComparator.java deleted file mode 100644 index 4b463161..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/DoubleShortComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two double, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface DoubleShortComparator { - int compare(double k1, short v1, double k2, short v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/FloatByteComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/FloatByteComparator.java deleted file mode 100644 index 298f94b0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/FloatByteComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two float, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface FloatByteComparator { - int compare(float k1, byte v1, float k2, byte v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/FloatCharComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/FloatCharComparator.java deleted file mode 100644 index a2af271b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/FloatCharComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two float, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface FloatCharComparator { - int compare(float k1, char v1, float k2, char v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/FloatComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/FloatComparator.java deleted file mode 100644 index 8831a3bc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/FloatComparator.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two float values. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") -public interface FloatComparator { - int compare(float a, float b); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/FloatDoubleComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/FloatDoubleComparator.java deleted file mode 100644 index 26cfcb64..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/FloatDoubleComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two float, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface FloatDoubleComparator { - int compare(float k1, double v1, float k2, double v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/FloatFloatComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/FloatFloatComparator.java deleted file mode 100644 index 8fc373bb..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/FloatFloatComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two float, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface FloatFloatComparator { - int compare(float k1, float v1, float k2, float v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/FloatIntComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/FloatIntComparator.java deleted file mode 100644 index 86199e53..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/FloatIntComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two float, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface FloatIntComparator { - int compare(float k1, int v1, float k2, int v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/FloatLongComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/FloatLongComparator.java deleted file mode 100644 index 7dcc9e44..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/FloatLongComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two float, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface FloatLongComparator { - int compare(float k1, long v1, float k2, long v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/FloatObjectComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/FloatObjectComparator.java deleted file mode 100644 index f1e9cd64..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/FloatObjectComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two float, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface FloatObjectComparator { - int compare(float k1, VType v1, float k2, VType v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/FloatShortComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/FloatShortComparator.java deleted file mode 100644 index baac7d4f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/FloatShortComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two float, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface FloatShortComparator { - int compare(float k1, short v1, float k2, short v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/IntByteComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/IntByteComparator.java deleted file mode 100644 index fe34ad58..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/IntByteComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two int, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface IntByteComparator { - int compare(int k1, byte v1, int k2, byte v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/IntCharComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/IntCharComparator.java deleted file mode 100644 index b682c529..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/IntCharComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two int, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface IntCharComparator { - int compare(int k1, char v1, int k2, char v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/IntComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/IntComparator.java deleted file mode 100644 index 3501d91a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/IntComparator.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two int values. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") -public interface IntComparator { - int compare(int a, int b); - - static IntComparator naturalOrder() { - return Integer::compare; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/IntDoubleComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/IntDoubleComparator.java deleted file mode 100644 index 5d6580d9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/IntDoubleComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two int, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface IntDoubleComparator { - int compare(int k1, double v1, int k2, double v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/IntFloatComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/IntFloatComparator.java deleted file mode 100644 index 6cb79069..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/IntFloatComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two int, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface IntFloatComparator { - int compare(int k1, float v1, int k2, float v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/IntIntComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/IntIntComparator.java deleted file mode 100644 index fe4214fc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/IntIntComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two int, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface IntIntComparator { - int compare(int k1, int v1, int k2, int v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/IntLongComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/IntLongComparator.java deleted file mode 100644 index 620a6978..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/IntLongComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two int, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface IntLongComparator { - int compare(int k1, long v1, int k2, long v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/IntObjectComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/IntObjectComparator.java deleted file mode 100644 index 8fbbb04c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/IntObjectComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two int, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface IntObjectComparator { - int compare(int k1, VType v1, int k2, VType v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/IntShortComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/IntShortComparator.java deleted file mode 100644 index 5657bdb0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/IntShortComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two int, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface IntShortComparator { - int compare(int k1, short v1, int k2, short v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/LongByteComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/LongByteComparator.java deleted file mode 100644 index 326d0f1c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/LongByteComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two long, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface LongByteComparator { - int compare(long k1, byte v1, long k2, byte v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/LongCharComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/LongCharComparator.java deleted file mode 100644 index 7c2267f5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/LongCharComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two long, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface LongCharComparator { - int compare(long k1, char v1, long k2, char v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/LongComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/LongComparator.java deleted file mode 100644 index d090607c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/LongComparator.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two long values. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") -public interface LongComparator { - int compare(long a, long b); - - static LongComparator naturalOrder() { - return Long::compare; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/LongDoubleComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/LongDoubleComparator.java deleted file mode 100644 index 25f39e20..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/LongDoubleComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two long, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface LongDoubleComparator { - int compare(long k1, double v1, long k2, double v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/LongFloatComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/LongFloatComparator.java deleted file mode 100644 index dde992f6..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/LongFloatComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two long, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface LongFloatComparator { - int compare(long k1, float v1, long k2, float v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/LongIntComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/LongIntComparator.java deleted file mode 100644 index de63af1d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/LongIntComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two long, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface LongIntComparator { - int compare(long k1, int v1, long k2, int v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/LongLongComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/LongLongComparator.java deleted file mode 100644 index 9b0822d8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/LongLongComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two long, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface LongLongComparator { - int compare(long k1, long v1, long k2, long v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/LongObjectComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/LongObjectComparator.java deleted file mode 100644 index 42fd64ba..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/LongObjectComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two long, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface LongObjectComparator { - int compare(long k1, VType v1, long k2, VType v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/LongShortComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/LongShortComparator.java deleted file mode 100644 index b6377dd2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/LongShortComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two long, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface LongShortComparator { - int compare(long k1, short v1, long k2, short v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectByteComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ObjectByteComparator.java deleted file mode 100644 index 54d86da0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectByteComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two Object, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ObjectByteComparator { - int compare(KType k1, byte v1, KType k2, byte v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectCharComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ObjectCharComparator.java deleted file mode 100644 index 0c8f42dc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectCharComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two Object, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ObjectCharComparator { - int compare(KType k1, char v1, KType k2, char v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectDoubleComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ObjectDoubleComparator.java deleted file mode 100644 index 1ec17275..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectDoubleComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two Object, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ObjectDoubleComparator { - int compare(KType k1, double v1, KType k2, double v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectFloatComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ObjectFloatComparator.java deleted file mode 100644 index 1c289f20..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectFloatComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two Object, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ObjectFloatComparator { - int compare(KType k1, float v1, KType k2, float v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectIntComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ObjectIntComparator.java deleted file mode 100644 index fe143279..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectIntComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two Object, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ObjectIntComparator { - int compare(KType k1, int v1, KType k2, int v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectLongComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ObjectLongComparator.java deleted file mode 100644 index e031f4ea..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectLongComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two Object, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ObjectLongComparator { - int compare(KType k1, long v1, KType k2, long v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectObjectComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ObjectObjectComparator.java deleted file mode 100644 index ed5a2d68..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectObjectComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two Object, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ObjectObjectComparator { - int compare(KType k1, VType v1, KType k2, VType v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectShortComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ObjectShortComparator.java deleted file mode 100644 index c545a557..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ObjectShortComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two Object, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ObjectShortComparator { - int compare(KType k1, short v1, KType k2, short v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ShortByteComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ShortByteComparator.java deleted file mode 100644 index b372f942..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ShortByteComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two short, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ShortByteComparator { - int compare(short k1, byte v1, short k2, byte v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ShortCharComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ShortCharComparator.java deleted file mode 100644 index 82b9b0a3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ShortCharComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two short, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ShortCharComparator { - int compare(short k1, char v1, short k2, char v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ShortComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ShortComparator.java deleted file mode 100644 index b935f60b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ShortComparator.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two short values. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") -public interface ShortComparator { - int compare(short a, short b); - - static ShortComparator naturalOrder() { - return Short::compare; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ShortDoubleComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ShortDoubleComparator.java deleted file mode 100644 index 37c2a7b5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ShortDoubleComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two short, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ShortDoubleComparator { - int compare(short k1, double v1, short k2, double v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ShortFloatComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ShortFloatComparator.java deleted file mode 100644 index 15eec4a8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ShortFloatComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two short, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ShortFloatComparator { - int compare(short k1, float v1, short k2, float v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ShortIntComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ShortIntComparator.java deleted file mode 100644 index 9d5ad1fe..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ShortIntComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two short, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ShortIntComparator { - int compare(short k1, int v1, short k2, int v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ShortLongComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ShortLongComparator.java deleted file mode 100644 index 9e394e1a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ShortLongComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two short, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ShortLongComparator { - int compare(short k1, long v1, short k2, long v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ShortObjectComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ShortObjectComparator.java deleted file mode 100644 index 6d1715f3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ShortObjectComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two short, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ShortObjectComparator { - int compare(short k1, VType v1, short k2, VType v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/comparators/ShortShortComparator.java b/sources/main/java/com/carrotsearch/hppc/comparators/ShortShortComparator.java deleted file mode 100644 index ccd78621..00000000 --- a/sources/main/java/com/carrotsearch/hppc/comparators/ShortShortComparator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.comparators; - -/** Compares two short, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:17+0200", - value = "KTypeVTypeComparator.java") -public interface ShortShortComparator { - int compare(short k1, short v1, short k2, short v2); -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ByteCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ByteCursor.java deleted file mode 100644 index e0b695dd..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ByteCursor.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over a collection of bytes. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") -public final class ByteCursor { - /** - * The current value's index in the container this cursor belongs to. The meaning of this index is - * defined by the container (usually it will be an index in the underlying storage buffer). - */ - public int index; - - /** The current value. */ - public byte value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/CharByteCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/CharByteCursor.java deleted file mode 100644 index 9e36f8f1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/CharByteCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (char keys and byte values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class CharByteCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public char key; - - /** The current value. */ - public byte value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/CharCharCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/CharCharCursor.java deleted file mode 100644 index 079a2682..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/CharCharCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (char keys and char values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class CharCharCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public char key; - - /** The current value. */ - public char value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/CharCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/CharCursor.java deleted file mode 100644 index 20a0ec58..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/CharCursor.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over a collection of chars. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") -public final class CharCursor { - /** - * The current value's index in the container this cursor belongs to. The meaning of this index is - * defined by the container (usually it will be an index in the underlying storage buffer). - */ - public int index; - - /** The current value. */ - public char value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/CharDoubleCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/CharDoubleCursor.java deleted file mode 100644 index 5cdcd581..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/CharDoubleCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (char keys and double values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class CharDoubleCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public char key; - - /** The current value. */ - public double value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/CharFloatCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/CharFloatCursor.java deleted file mode 100644 index 109f0ae3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/CharFloatCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (char keys and float values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class CharFloatCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public char key; - - /** The current value. */ - public float value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/CharIntCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/CharIntCursor.java deleted file mode 100644 index b706f1f4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/CharIntCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (char keys and int values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class CharIntCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public char key; - - /** The current value. */ - public int value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/CharLongCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/CharLongCursor.java deleted file mode 100644 index 1d5259ff..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/CharLongCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (char keys and long values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class CharLongCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public char key; - - /** The current value. */ - public long value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/CharObjectCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/CharObjectCursor.java deleted file mode 100644 index fa98d620..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/CharObjectCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (char keys and Object values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class CharObjectCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public char key; - - /** The current value. */ - public VType value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/CharShortCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/CharShortCursor.java deleted file mode 100644 index d6407c80..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/CharShortCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (char keys and short values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class CharShortCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public char key; - - /** The current value. */ - public short value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/DoubleCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/DoubleCursor.java deleted file mode 100644 index cc4f42c9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/DoubleCursor.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over a collection of doubles. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") -public final class DoubleCursor { - /** - * The current value's index in the container this cursor belongs to. The meaning of this index is - * defined by the container (usually it will be an index in the underlying storage buffer). - */ - public int index; - - /** The current value. */ - public double value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/FloatCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/FloatCursor.java deleted file mode 100644 index 417f27eb..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/FloatCursor.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over a collection of floats. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") -public final class FloatCursor { - /** - * The current value's index in the container this cursor belongs to. The meaning of this index is - * defined by the container (usually it will be an index in the underlying storage buffer). - */ - public int index; - - /** The current value. */ - public float value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/IntByteCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/IntByteCursor.java deleted file mode 100644 index b0dede73..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/IntByteCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (int keys and byte values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class IntByteCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public int key; - - /** The current value. */ - public byte value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/IntCharCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/IntCharCursor.java deleted file mode 100644 index d49fd001..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/IntCharCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (int keys and char values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class IntCharCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public int key; - - /** The current value. */ - public char value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/IntCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/IntCursor.java deleted file mode 100644 index 8fd34781..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/IntCursor.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over a collection of ints. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") -public final class IntCursor { - /** - * The current value's index in the container this cursor belongs to. The meaning of this index is - * defined by the container (usually it will be an index in the underlying storage buffer). - */ - public int index; - - /** The current value. */ - public int value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/IntDoubleCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/IntDoubleCursor.java deleted file mode 100644 index 03e56888..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/IntDoubleCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (int keys and double values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class IntDoubleCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public int key; - - /** The current value. */ - public double value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/IntFloatCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/IntFloatCursor.java deleted file mode 100644 index 0cbc76e1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/IntFloatCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (int keys and float values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class IntFloatCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public int key; - - /** The current value. */ - public float value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/IntIntCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/IntIntCursor.java deleted file mode 100644 index c02ea79e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/IntIntCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (int keys and int values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class IntIntCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public int key; - - /** The current value. */ - public int value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/IntLongCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/IntLongCursor.java deleted file mode 100644 index 299ad712..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/IntLongCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (int keys and long values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class IntLongCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public int key; - - /** The current value. */ - public long value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/IntObjectCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/IntObjectCursor.java deleted file mode 100644 index 673a06d1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/IntObjectCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (int keys and Object values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class IntObjectCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public int key; - - /** The current value. */ - public VType value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/IntShortCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/IntShortCursor.java deleted file mode 100644 index 7f72eba4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/IntShortCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (int keys and short values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class IntShortCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public int key; - - /** The current value. */ - public short value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/LongByteCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/LongByteCursor.java deleted file mode 100644 index 74cdbd90..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/LongByteCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (long keys and byte values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class LongByteCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public long key; - - /** The current value. */ - public byte value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/LongCharCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/LongCharCursor.java deleted file mode 100644 index 800389a1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/LongCharCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (long keys and char values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class LongCharCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public long key; - - /** The current value. */ - public char value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/LongCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/LongCursor.java deleted file mode 100644 index 53da311c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/LongCursor.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over a collection of longs. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") -public final class LongCursor { - /** - * The current value's index in the container this cursor belongs to. The meaning of this index is - * defined by the container (usually it will be an index in the underlying storage buffer). - */ - public int index; - - /** The current value. */ - public long value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/LongDoubleCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/LongDoubleCursor.java deleted file mode 100644 index ed4ceef2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/LongDoubleCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (long keys and double values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class LongDoubleCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public long key; - - /** The current value. */ - public double value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/LongFloatCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/LongFloatCursor.java deleted file mode 100644 index 0ff3ebb7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/LongFloatCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (long keys and float values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class LongFloatCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public long key; - - /** The current value. */ - public float value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/LongIntCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/LongIntCursor.java deleted file mode 100644 index 202d409a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/LongIntCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (long keys and int values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class LongIntCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public long key; - - /** The current value. */ - public int value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/LongLongCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/LongLongCursor.java deleted file mode 100644 index 824852f8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/LongLongCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (long keys and long values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class LongLongCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public long key; - - /** The current value. */ - public long value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/LongObjectCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/LongObjectCursor.java deleted file mode 100644 index 26f413c0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/LongObjectCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (long keys and Object values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class LongObjectCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public long key; - - /** The current value. */ - public VType value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/LongShortCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/LongShortCursor.java deleted file mode 100644 index 5d82d4e5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/LongShortCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (long keys and short values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class LongShortCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public long key; - - /** The current value. */ - public short value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectByteCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ObjectByteCursor.java deleted file mode 100644 index 380b48af..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectByteCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (Object keys and byte values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ObjectByteCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public KType key; - - /** The current value. */ - public byte value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectCharCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ObjectCharCursor.java deleted file mode 100644 index 1e4df4fc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectCharCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (Object keys and char values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ObjectCharCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public KType key; - - /** The current value. */ - public char value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ObjectCursor.java deleted file mode 100644 index 9f3ef5c0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectCursor.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over a collection of Objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") -public final class ObjectCursor { - /** - * The current value's index in the container this cursor belongs to. The meaning of this index is - * defined by the container (usually it will be an index in the underlying storage buffer). - */ - public int index; - - /** The current value. */ - public KType value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectDoubleCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ObjectDoubleCursor.java deleted file mode 100644 index edc16aea..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectDoubleCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (Object keys and double values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ObjectDoubleCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public KType key; - - /** The current value. */ - public double value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectFloatCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ObjectFloatCursor.java deleted file mode 100644 index 767777e4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectFloatCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (Object keys and float values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ObjectFloatCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public KType key; - - /** The current value. */ - public float value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectIntCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ObjectIntCursor.java deleted file mode 100644 index b83b3672..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectIntCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (Object keys and int values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ObjectIntCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public KType key; - - /** The current value. */ - public int value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectLongCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ObjectLongCursor.java deleted file mode 100644 index 4eba0b0b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectLongCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (Object keys and long values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ObjectLongCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public KType key; - - /** The current value. */ - public long value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectObjectCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ObjectObjectCursor.java deleted file mode 100644 index 85514da4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectObjectCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (Object keys and Object values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ObjectObjectCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public KType key; - - /** The current value. */ - public VType value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectShortCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ObjectShortCursor.java deleted file mode 100644 index 30f6fa60..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ObjectShortCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (Object keys and short values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ObjectShortCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public KType key; - - /** The current value. */ - public short value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ShortByteCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ShortByteCursor.java deleted file mode 100644 index 1a2bd555..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ShortByteCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (short keys and byte values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ShortByteCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public short key; - - /** The current value. */ - public byte value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ShortCharCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ShortCharCursor.java deleted file mode 100644 index 120fd566..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ShortCharCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (short keys and char values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ShortCharCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public short key; - - /** The current value. */ - public char value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ShortCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ShortCursor.java deleted file mode 100644 index 37117970..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ShortCursor.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over a collection of shorts. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") -public final class ShortCursor { - /** - * The current value's index in the container this cursor belongs to. The meaning of this index is - * defined by the container (usually it will be an index in the underlying storage buffer). - */ - public int index; - - /** The current value. */ - public short value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ShortDoubleCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ShortDoubleCursor.java deleted file mode 100644 index f4b2d389..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ShortDoubleCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (short keys and double values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ShortDoubleCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public short key; - - /** The current value. */ - public double value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ShortFloatCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ShortFloatCursor.java deleted file mode 100644 index 8a605078..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ShortFloatCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (short keys and float values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ShortFloatCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public short key; - - /** The current value. */ - public float value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ShortIntCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ShortIntCursor.java deleted file mode 100644 index 997a6792..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ShortIntCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (short keys and int values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ShortIntCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public short key; - - /** The current value. */ - public int value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ShortLongCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ShortLongCursor.java deleted file mode 100644 index 576e7f0e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ShortLongCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (short keys and long values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ShortLongCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public short key; - - /** The current value. */ - public long value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ShortObjectCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ShortObjectCursor.java deleted file mode 100644 index 485514f6..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ShortObjectCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (short keys and Object values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ShortObjectCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public short key; - - /** The current value. */ - public VType value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/cursors/ShortShortCursor.java b/sources/main/java/com/carrotsearch/hppc/cursors/ShortShortCursor.java deleted file mode 100644 index 5fa724eb..00000000 --- a/sources/main/java/com/carrotsearch/hppc/cursors/ShortShortCursor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.carrotsearch.hppc.cursors; - -/** A cursor over entries of an associative container (short keys and short values). */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") -public final class ShortShortCursor { - /** - * The current key and value's index in the container this cursor belongs to. The meaning of this - * index is defined by the container (usually it will be an index in the underlying storage - * buffer). - */ - public int index; - - /** The current key. */ - public short key; - - /** The current value. */ - public short value; - - @Override - public String toString() { - return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/internals/SuppressForbidden.java b/sources/main/java/com/carrotsearch/hppc/internals/SuppressForbidden.java deleted file mode 100644 index c746e0f7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/internals/SuppressForbidden.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc.internals; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Suppresses forbidden-API checks. */ -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) -public @interface SuppressForbidden {} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ByteBytePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ByteBytePredicate.java deleted file mode 100644 index d3819903..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ByteBytePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to byte, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ByteBytePredicate { - public boolean apply(byte key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ByteCharPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ByteCharPredicate.java deleted file mode 100644 index 7e1877cc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ByteCharPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to byte, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ByteCharPredicate { - public boolean apply(byte key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ByteDoublePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ByteDoublePredicate.java deleted file mode 100644 index 598b185b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ByteDoublePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to byte, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ByteDoublePredicate { - public boolean apply(byte key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ByteFloatPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ByteFloatPredicate.java deleted file mode 100644 index 0a7dde15..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ByteFloatPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to byte, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ByteFloatPredicate { - public boolean apply(byte key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ByteIntPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ByteIntPredicate.java deleted file mode 100644 index 8b523f51..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ByteIntPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to byte, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ByteIntPredicate { - public boolean apply(byte key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ByteLongPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ByteLongPredicate.java deleted file mode 100644 index bff16b84..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ByteLongPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to byte, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ByteLongPredicate { - public boolean apply(byte key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ByteObjectPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ByteObjectPredicate.java deleted file mode 100644 index 322f132b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ByteObjectPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to byte, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ByteObjectPredicate { - public boolean apply(byte key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/BytePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/BytePredicate.java deleted file mode 100644 index 16c023b1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/BytePredicate.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to byte objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") -public interface BytePredicate { - public boolean apply(byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ByteShortPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ByteShortPredicate.java deleted file mode 100644 index 975073f7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ByteShortPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to byte, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ByteShortPredicate { - public boolean apply(byte key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/CharBytePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/CharBytePredicate.java deleted file mode 100644 index 1bd258e4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/CharBytePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to char, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface CharBytePredicate { - public boolean apply(char key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/CharCharPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/CharCharPredicate.java deleted file mode 100644 index b2142e99..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/CharCharPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to char, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface CharCharPredicate { - public boolean apply(char key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/CharDoublePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/CharDoublePredicate.java deleted file mode 100644 index d7409d75..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/CharDoublePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to char, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface CharDoublePredicate { - public boolean apply(char key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/CharFloatPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/CharFloatPredicate.java deleted file mode 100644 index d2e3c890..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/CharFloatPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to char, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface CharFloatPredicate { - public boolean apply(char key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/CharIntPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/CharIntPredicate.java deleted file mode 100644 index e68d9dac..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/CharIntPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to char, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface CharIntPredicate { - public boolean apply(char key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/CharLongPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/CharLongPredicate.java deleted file mode 100644 index de3ed2dc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/CharLongPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to char, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface CharLongPredicate { - public boolean apply(char key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/CharObjectPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/CharObjectPredicate.java deleted file mode 100644 index c85875e6..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/CharObjectPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to char, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface CharObjectPredicate { - public boolean apply(char key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/CharPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/CharPredicate.java deleted file mode 100644 index efe6e9dc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/CharPredicate.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to char objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") -public interface CharPredicate { - public boolean apply(char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/CharShortPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/CharShortPredicate.java deleted file mode 100644 index 54d462c2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/CharShortPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to char, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface CharShortPredicate { - public boolean apply(char key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleBytePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/DoubleBytePredicate.java deleted file mode 100644 index 1ab1d41c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleBytePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to double, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface DoubleBytePredicate { - public boolean apply(double key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleCharPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/DoubleCharPredicate.java deleted file mode 100644 index ac7f394e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleCharPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to double, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface DoubleCharPredicate { - public boolean apply(double key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleDoublePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/DoubleDoublePredicate.java deleted file mode 100644 index d3e39487..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleDoublePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to double, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface DoubleDoublePredicate { - public boolean apply(double key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleFloatPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/DoubleFloatPredicate.java deleted file mode 100644 index 1a0343d8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleFloatPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to double, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface DoubleFloatPredicate { - public boolean apply(double key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleIntPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/DoubleIntPredicate.java deleted file mode 100644 index a1a135be..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleIntPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to double, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface DoubleIntPredicate { - public boolean apply(double key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleLongPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/DoubleLongPredicate.java deleted file mode 100644 index 2014b2a1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleLongPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to double, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface DoubleLongPredicate { - public boolean apply(double key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleObjectPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/DoubleObjectPredicate.java deleted file mode 100644 index 290912f9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleObjectPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to double, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface DoubleObjectPredicate { - public boolean apply(double key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/DoublePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/DoublePredicate.java deleted file mode 100644 index 57227e9f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/DoublePredicate.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to double objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") -public interface DoublePredicate { - public boolean apply(double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleShortPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/DoubleShortPredicate.java deleted file mode 100644 index 6ee48dbf..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/DoubleShortPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to double, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface DoubleShortPredicate { - public boolean apply(double key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/FloatBytePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/FloatBytePredicate.java deleted file mode 100644 index 07a763b5..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/FloatBytePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to float, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface FloatBytePredicate { - public boolean apply(float key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/FloatCharPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/FloatCharPredicate.java deleted file mode 100644 index a14461d7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/FloatCharPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to float, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface FloatCharPredicate { - public boolean apply(float key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/FloatDoublePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/FloatDoublePredicate.java deleted file mode 100644 index 8c8dda0d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/FloatDoublePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to float, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface FloatDoublePredicate { - public boolean apply(float key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/FloatFloatPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/FloatFloatPredicate.java deleted file mode 100644 index fae9df7a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/FloatFloatPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to float, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface FloatFloatPredicate { - public boolean apply(float key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/FloatIntPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/FloatIntPredicate.java deleted file mode 100644 index dd37320b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/FloatIntPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to float, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface FloatIntPredicate { - public boolean apply(float key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/FloatLongPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/FloatLongPredicate.java deleted file mode 100644 index ed1232a7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/FloatLongPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to float, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface FloatLongPredicate { - public boolean apply(float key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/FloatObjectPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/FloatObjectPredicate.java deleted file mode 100644 index a74dca85..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/FloatObjectPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to float, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface FloatObjectPredicate { - public boolean apply(float key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/FloatPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/FloatPredicate.java deleted file mode 100644 index eb728862..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/FloatPredicate.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to float objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") -public interface FloatPredicate { - public boolean apply(float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/FloatShortPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/FloatShortPredicate.java deleted file mode 100644 index 1a61beb0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/FloatShortPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to float, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface FloatShortPredicate { - public boolean apply(float key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/IntBytePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/IntBytePredicate.java deleted file mode 100644 index 3bfa0aac..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/IntBytePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to int, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface IntBytePredicate { - public boolean apply(int key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/IntCharPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/IntCharPredicate.java deleted file mode 100644 index c262f415..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/IntCharPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to int, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface IntCharPredicate { - public boolean apply(int key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/IntDoublePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/IntDoublePredicate.java deleted file mode 100644 index 3ec64db1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/IntDoublePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to int, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface IntDoublePredicate { - public boolean apply(int key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/IntFloatPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/IntFloatPredicate.java deleted file mode 100644 index 449b5f0d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/IntFloatPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to int, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface IntFloatPredicate { - public boolean apply(int key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/IntIntPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/IntIntPredicate.java deleted file mode 100644 index 384d33cd..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/IntIntPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to int, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface IntIntPredicate { - public boolean apply(int key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/IntLongPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/IntLongPredicate.java deleted file mode 100644 index f3d4811b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/IntLongPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to int, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface IntLongPredicate { - public boolean apply(int key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/IntObjectPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/IntObjectPredicate.java deleted file mode 100644 index 5a8063a8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/IntObjectPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to int, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface IntObjectPredicate { - public boolean apply(int key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/IntPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/IntPredicate.java deleted file mode 100644 index 77d1c38f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/IntPredicate.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to int objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") -public interface IntPredicate { - public boolean apply(int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/IntShortPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/IntShortPredicate.java deleted file mode 100644 index 443642d7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/IntShortPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to int, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface IntShortPredicate { - public boolean apply(int key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/LongBytePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/LongBytePredicate.java deleted file mode 100644 index dce65d8e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/LongBytePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to long, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface LongBytePredicate { - public boolean apply(long key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/LongCharPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/LongCharPredicate.java deleted file mode 100644 index f2974d72..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/LongCharPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to long, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface LongCharPredicate { - public boolean apply(long key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/LongDoublePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/LongDoublePredicate.java deleted file mode 100644 index 34947e08..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/LongDoublePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to long, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface LongDoublePredicate { - public boolean apply(long key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/LongFloatPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/LongFloatPredicate.java deleted file mode 100644 index c0bf1e54..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/LongFloatPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to long, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface LongFloatPredicate { - public boolean apply(long key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/LongIntPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/LongIntPredicate.java deleted file mode 100644 index a31d293a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/LongIntPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to long, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface LongIntPredicate { - public boolean apply(long key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/LongLongPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/LongLongPredicate.java deleted file mode 100644 index 45315193..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/LongLongPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to long, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface LongLongPredicate { - public boolean apply(long key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/LongObjectPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/LongObjectPredicate.java deleted file mode 100644 index fef9bbc3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/LongObjectPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to long, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface LongObjectPredicate { - public boolean apply(long key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/LongPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/LongPredicate.java deleted file mode 100644 index 52f0b87a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/LongPredicate.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to long objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") -public interface LongPredicate { - public boolean apply(long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/LongShortPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/LongShortPredicate.java deleted file mode 100644 index 5621fd73..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/LongShortPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to long, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface LongShortPredicate { - public boolean apply(long key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectBytePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ObjectBytePredicate.java deleted file mode 100644 index 57657903..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectBytePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to Object, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ObjectBytePredicate { - public boolean apply(KType key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectCharPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ObjectCharPredicate.java deleted file mode 100644 index 2c108dbb..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectCharPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to Object, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ObjectCharPredicate { - public boolean apply(KType key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectDoublePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ObjectDoublePredicate.java deleted file mode 100644 index e8d4ff50..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectDoublePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to Object, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ObjectDoublePredicate { - public boolean apply(KType key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectFloatPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ObjectFloatPredicate.java deleted file mode 100644 index 166d0c56..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectFloatPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to Object, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ObjectFloatPredicate { - public boolean apply(KType key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectIntPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ObjectIntPredicate.java deleted file mode 100644 index d683332c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectIntPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to Object, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ObjectIntPredicate { - public boolean apply(KType key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectLongPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ObjectLongPredicate.java deleted file mode 100644 index bd97d954..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectLongPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to Object, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ObjectLongPredicate { - public boolean apply(KType key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectObjectPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ObjectObjectPredicate.java deleted file mode 100644 index 6970aa65..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectObjectPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to Object, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ObjectObjectPredicate { - public boolean apply(KType key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ObjectPredicate.java deleted file mode 100644 index c9426651..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectPredicate.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to Object objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") -public interface ObjectPredicate { - public boolean apply(KType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectShortPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ObjectShortPredicate.java deleted file mode 100644 index 2049fabf..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ObjectShortPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to Object, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ObjectShortPredicate { - public boolean apply(KType key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ShortBytePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ShortBytePredicate.java deleted file mode 100644 index 86305fa4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ShortBytePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to short, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ShortBytePredicate { - public boolean apply(short key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ShortCharPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ShortCharPredicate.java deleted file mode 100644 index 14a726ef..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ShortCharPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to short, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ShortCharPredicate { - public boolean apply(short key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ShortDoublePredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ShortDoublePredicate.java deleted file mode 100644 index 1fdd8733..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ShortDoublePredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to short, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ShortDoublePredicate { - public boolean apply(short key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ShortFloatPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ShortFloatPredicate.java deleted file mode 100644 index 4a55b962..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ShortFloatPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to short, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ShortFloatPredicate { - public boolean apply(short key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ShortIntPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ShortIntPredicate.java deleted file mode 100644 index 039c59ab..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ShortIntPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to short, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ShortIntPredicate { - public boolean apply(short key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ShortLongPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ShortLongPredicate.java deleted file mode 100644 index 7036942c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ShortLongPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to short, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ShortLongPredicate { - public boolean apply(short key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ShortObjectPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ShortObjectPredicate.java deleted file mode 100644 index 1b4bf8b7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ShortObjectPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to short, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ShortObjectPredicate { - public boolean apply(short key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ShortPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ShortPredicate.java deleted file mode 100644 index 40fa91c8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ShortPredicate.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to short objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") -public interface ShortPredicate { - public boolean apply(short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/predicates/ShortShortPredicate.java b/sources/main/java/com/carrotsearch/hppc/predicates/ShortShortPredicate.java deleted file mode 100644 index 51d7b0a7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/predicates/ShortShortPredicate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.predicates; - -/** A predicate that applies to short, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypePredicate.java") -public interface ShortShortPredicate { - public boolean apply(short key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ByteByteProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ByteByteProcedure.java deleted file mode 100644 index bd4a18ef..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ByteByteProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to byte, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ByteByteProcedure { - public void apply(byte key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ByteCharProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ByteCharProcedure.java deleted file mode 100644 index 6b4c5dea..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ByteCharProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to byte, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ByteCharProcedure { - public void apply(byte key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ByteDoubleProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ByteDoubleProcedure.java deleted file mode 100644 index 3269170a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ByteDoubleProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to byte, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ByteDoubleProcedure { - public void apply(byte key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ByteFloatProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ByteFloatProcedure.java deleted file mode 100644 index 011427e7..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ByteFloatProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to byte, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ByteFloatProcedure { - public void apply(byte key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ByteIntProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ByteIntProcedure.java deleted file mode 100644 index aca3dc2f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ByteIntProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to byte, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ByteIntProcedure { - public void apply(byte key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ByteLongProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ByteLongProcedure.java deleted file mode 100644 index 01e9239e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ByteLongProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to byte, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ByteLongProcedure { - public void apply(byte key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ByteObjectProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ByteObjectProcedure.java deleted file mode 100644 index 8d954b0d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ByteObjectProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to byte, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ByteObjectProcedure { - public void apply(byte key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ByteProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ByteProcedure.java deleted file mode 100644 index 9959f0d1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ByteProcedure.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to byte objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") -public interface ByteProcedure { - public void apply(byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ByteShortProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ByteShortProcedure.java deleted file mode 100644 index 83e34cc9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ByteShortProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to byte, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ByteShortProcedure { - public void apply(byte key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/CharByteProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/CharByteProcedure.java deleted file mode 100644 index 58fa2d40..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/CharByteProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to char, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface CharByteProcedure { - public void apply(char key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/CharCharProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/CharCharProcedure.java deleted file mode 100644 index 2cd5d298..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/CharCharProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to char, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface CharCharProcedure { - public void apply(char key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/CharDoubleProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/CharDoubleProcedure.java deleted file mode 100644 index 091e5c9d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/CharDoubleProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to char, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface CharDoubleProcedure { - public void apply(char key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/CharFloatProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/CharFloatProcedure.java deleted file mode 100644 index 73b54532..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/CharFloatProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to char, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface CharFloatProcedure { - public void apply(char key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/CharIntProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/CharIntProcedure.java deleted file mode 100644 index 8118508d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/CharIntProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to char, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface CharIntProcedure { - public void apply(char key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/CharLongProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/CharLongProcedure.java deleted file mode 100644 index 9657edd1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/CharLongProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to char, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface CharLongProcedure { - public void apply(char key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/CharObjectProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/CharObjectProcedure.java deleted file mode 100644 index 145e6f7d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/CharObjectProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to char, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface CharObjectProcedure { - public void apply(char key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/CharProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/CharProcedure.java deleted file mode 100644 index 2bd7e5d3..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/CharProcedure.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to char objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") -public interface CharProcedure { - public void apply(char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/CharShortProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/CharShortProcedure.java deleted file mode 100644 index 50b2584f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/CharShortProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to char, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface CharShortProcedure { - public void apply(char key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleByteProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/DoubleByteProcedure.java deleted file mode 100644 index 70adadf6..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleByteProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to double, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface DoubleByteProcedure { - public void apply(double key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleCharProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/DoubleCharProcedure.java deleted file mode 100644 index 101e0d99..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleCharProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to double, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface DoubleCharProcedure { - public void apply(double key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleDoubleProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/DoubleDoubleProcedure.java deleted file mode 100644 index 9ba2012c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleDoubleProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to double, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface DoubleDoubleProcedure { - public void apply(double key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleFloatProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/DoubleFloatProcedure.java deleted file mode 100644 index 3dabb0c9..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleFloatProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to double, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface DoubleFloatProcedure { - public void apply(double key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleIntProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/DoubleIntProcedure.java deleted file mode 100644 index be62b25a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleIntProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to double, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface DoubleIntProcedure { - public void apply(double key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleLongProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/DoubleLongProcedure.java deleted file mode 100644 index a648e97a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleLongProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to double, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface DoubleLongProcedure { - public void apply(double key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleObjectProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/DoubleObjectProcedure.java deleted file mode 100644 index 5973dd22..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleObjectProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to double, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface DoubleObjectProcedure { - public void apply(double key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/DoubleProcedure.java deleted file mode 100644 index c23a5617..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleProcedure.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to double objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") -public interface DoubleProcedure { - public void apply(double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleShortProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/DoubleShortProcedure.java deleted file mode 100644 index aea0b9ec..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/DoubleShortProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to double, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface DoubleShortProcedure { - public void apply(double key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/FloatByteProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/FloatByteProcedure.java deleted file mode 100644 index df914d43..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/FloatByteProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to float, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface FloatByteProcedure { - public void apply(float key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/FloatCharProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/FloatCharProcedure.java deleted file mode 100644 index 8d54dba1..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/FloatCharProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to float, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface FloatCharProcedure { - public void apply(float key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/FloatDoubleProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/FloatDoubleProcedure.java deleted file mode 100644 index e398c47f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/FloatDoubleProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to float, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface FloatDoubleProcedure { - public void apply(float key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/FloatFloatProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/FloatFloatProcedure.java deleted file mode 100644 index 00cfa5b4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/FloatFloatProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to float, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface FloatFloatProcedure { - public void apply(float key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/FloatIntProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/FloatIntProcedure.java deleted file mode 100644 index f09f375d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/FloatIntProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to float, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface FloatIntProcedure { - public void apply(float key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/FloatLongProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/FloatLongProcedure.java deleted file mode 100644 index ee7e3d89..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/FloatLongProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to float, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface FloatLongProcedure { - public void apply(float key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/FloatObjectProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/FloatObjectProcedure.java deleted file mode 100644 index 3e23e199..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/FloatObjectProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to float, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface FloatObjectProcedure { - public void apply(float key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/FloatProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/FloatProcedure.java deleted file mode 100644 index 17543434..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/FloatProcedure.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to float objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") -public interface FloatProcedure { - public void apply(float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/FloatShortProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/FloatShortProcedure.java deleted file mode 100644 index 9ae0b7f8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/FloatShortProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to float, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface FloatShortProcedure { - public void apply(float key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/IntByteProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/IntByteProcedure.java deleted file mode 100644 index 2232f85a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/IntByteProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to int, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface IntByteProcedure { - public void apply(int key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/IntCharProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/IntCharProcedure.java deleted file mode 100644 index f5f1d509..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/IntCharProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to int, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface IntCharProcedure { - public void apply(int key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/IntDoubleProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/IntDoubleProcedure.java deleted file mode 100644 index 1fca14bb..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/IntDoubleProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to int, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface IntDoubleProcedure { - public void apply(int key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/IntFloatProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/IntFloatProcedure.java deleted file mode 100644 index 8c91a104..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/IntFloatProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to int, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface IntFloatProcedure { - public void apply(int key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/IntIntProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/IntIntProcedure.java deleted file mode 100644 index b870c6b8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/IntIntProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to int, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface IntIntProcedure { - public void apply(int key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/IntLongProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/IntLongProcedure.java deleted file mode 100644 index 741858f0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/IntLongProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to int, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface IntLongProcedure { - public void apply(int key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/IntObjectProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/IntObjectProcedure.java deleted file mode 100644 index 575a1f2a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/IntObjectProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to int, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface IntObjectProcedure { - public void apply(int key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/IntProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/IntProcedure.java deleted file mode 100644 index 4fab32fd..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/IntProcedure.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to int objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") -public interface IntProcedure { - public void apply(int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/IntShortProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/IntShortProcedure.java deleted file mode 100644 index c3bac031..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/IntShortProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to int, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface IntShortProcedure { - public void apply(int key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/LongByteProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/LongByteProcedure.java deleted file mode 100644 index 670af78b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/LongByteProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to long, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface LongByteProcedure { - public void apply(long key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/LongCharProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/LongCharProcedure.java deleted file mode 100644 index 5ca456d0..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/LongCharProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to long, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface LongCharProcedure { - public void apply(long key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/LongDoubleProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/LongDoubleProcedure.java deleted file mode 100644 index 2aaa2c3d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/LongDoubleProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to long, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface LongDoubleProcedure { - public void apply(long key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/LongFloatProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/LongFloatProcedure.java deleted file mode 100644 index 6b88a579..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/LongFloatProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to long, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface LongFloatProcedure { - public void apply(long key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/LongIntProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/LongIntProcedure.java deleted file mode 100644 index 297f3878..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/LongIntProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to long, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface LongIntProcedure { - public void apply(long key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/LongLongProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/LongLongProcedure.java deleted file mode 100644 index f9f1fba4..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/LongLongProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to long, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface LongLongProcedure { - public void apply(long key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/LongObjectProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/LongObjectProcedure.java deleted file mode 100644 index 2e0a8f86..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/LongObjectProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to long, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface LongObjectProcedure { - public void apply(long key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/LongProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/LongProcedure.java deleted file mode 100644 index 9397055f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/LongProcedure.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to long objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") -public interface LongProcedure { - public void apply(long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/LongShortProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/LongShortProcedure.java deleted file mode 100644 index 2ad0865a..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/LongShortProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to long, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface LongShortProcedure { - public void apply(long key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectByteProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ObjectByteProcedure.java deleted file mode 100644 index 85d69130..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectByteProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to Object, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ObjectByteProcedure { - public void apply(KType key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectCharProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ObjectCharProcedure.java deleted file mode 100644 index 3393875f..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectCharProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to Object, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ObjectCharProcedure { - public void apply(KType key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectDoubleProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ObjectDoubleProcedure.java deleted file mode 100644 index 4d9345d2..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectDoubleProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to Object, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ObjectDoubleProcedure { - public void apply(KType key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectFloatProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ObjectFloatProcedure.java deleted file mode 100644 index 237c2863..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectFloatProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to Object, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ObjectFloatProcedure { - public void apply(KType key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectIntProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ObjectIntProcedure.java deleted file mode 100644 index 11bb001c..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectIntProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to Object, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ObjectIntProcedure { - public void apply(KType key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectLongProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ObjectLongProcedure.java deleted file mode 100644 index 9aec4cdd..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectLongProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to Object, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ObjectLongProcedure { - public void apply(KType key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectObjectProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ObjectObjectProcedure.java deleted file mode 100644 index 382d76f8..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectObjectProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to Object, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ObjectObjectProcedure { - public void apply(KType key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ObjectProcedure.java deleted file mode 100644 index cb0f00fc..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectProcedure.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to Object objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") -public interface ObjectProcedure { - public void apply(KType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectShortProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ObjectShortProcedure.java deleted file mode 100644 index 871cac43..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ObjectShortProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to Object, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ObjectShortProcedure { - public void apply(KType key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ShortByteProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ShortByteProcedure.java deleted file mode 100644 index a9b86f29..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ShortByteProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to short, byte pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ShortByteProcedure { - public void apply(short key, byte value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ShortCharProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ShortCharProcedure.java deleted file mode 100644 index 2ebbb819..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ShortCharProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to short, char pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ShortCharProcedure { - public void apply(short key, char value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ShortDoubleProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ShortDoubleProcedure.java deleted file mode 100644 index ada12e27..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ShortDoubleProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to short, double pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ShortDoubleProcedure { - public void apply(short key, double value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ShortFloatProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ShortFloatProcedure.java deleted file mode 100644 index a99af694..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ShortFloatProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to short, float pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ShortFloatProcedure { - public void apply(short key, float value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ShortIntProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ShortIntProcedure.java deleted file mode 100644 index e633c55d..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ShortIntProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to short, int pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ShortIntProcedure { - public void apply(short key, int value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ShortLongProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ShortLongProcedure.java deleted file mode 100644 index 99275f7e..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ShortLongProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to short, long pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ShortLongProcedure { - public void apply(short key, long value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ShortObjectProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ShortObjectProcedure.java deleted file mode 100644 index 5ab91d02..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ShortObjectProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to short, Object pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ShortObjectProcedure { - public void apply(short key, VType value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ShortProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ShortProcedure.java deleted file mode 100644 index d3482c7b..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ShortProcedure.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to short objects. */ -@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") -public interface ShortProcedure { - public void apply(short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/procedures/ShortShortProcedure.java b/sources/main/java/com/carrotsearch/hppc/procedures/ShortShortProcedure.java deleted file mode 100644 index 05873e51..00000000 --- a/sources/main/java/com/carrotsearch/hppc/procedures/ShortShortProcedure.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.carrotsearch.hppc.procedures; - -/** A procedure that applies to short, short pairs. */ -@com.carrotsearch.hppc.Generated( - date = "2024-06-04T15:20:16+0200", - value = "KTypeVTypeProcedure.java") -public interface ShortShortProcedure { - public void apply(short key, short value); -} diff --git a/sources/main/java/com/carrotsearch/hppc/sorting/IndirectSort.java b/sources/main/java/com/carrotsearch/hppc/sorting/IndirectSort.java deleted file mode 100644 index 2d4722ed..00000000 --- a/sources/main/java/com/carrotsearch/hppc/sorting/IndirectSort.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc.sorting; - -import java.util.Comparator; -import java.util.function.IntBinaryOperator; - -/** - * Sorting routines that return an array of sorted indices implied by a given comparator rather than - * move elements of whatever the comparator is using for comparisons. - * - *

A practical use case for this class is when the index of an array is meaningful and one wants - * to acquire the order of values in that array. None of the methods in Java Collections would - * provide such functionality directly and creating a collection of boxed {@link Integer} objects - * for indices seems to be too costly. - */ -public final class IndirectSort { - /** Minimum window length to apply insertion sort in merge sort. */ - static int MIN_LENGTH_FOR_INSERTION_SORT = 30; - - /** No instantiation. */ - private IndirectSort() { - // No instantiation. - } - - /** - * Returns the order of elements between indices start and length, as - * indicated by the given comparator. - * - *

This routine uses merge sort. It is guaranteed to be stable. It creates a new indices array, - * and clones it while sorting. - */ - public static int[] mergesort(int start, int length, IntBinaryOperator comparator) { - final int[] src = createOrderArray(start, length); - return mergesort(src, comparator); - } - - /** - * Returns a sorted copy of the order array provided, using the given comparator. - * - *

This routine uses merge sort. It is guaranteed to be stable. The provided {@code - * indicesArray} is cloned while sorting and the clone is returned. - */ - public static int[] mergesort(int[] orderArray, IntBinaryOperator comparator) { - if (orderArray.length <= 1) { - return orderArray; - } - final int[] dst = orderArray.clone(); - topDownMergeSort(orderArray, dst, 0, orderArray.length, comparator); - return dst; - } - - /** - * Returns the order of elements between indices start and length, as - * indicated by the given comparator. - * - *

This routine uses merge sort. It is guaranteed to be stable. It creates a new indices array, - * and clones it while sorting. - */ - public static int[] mergesort( - T[] input, int start, int length, Comparator comparator) { - return mergesort(start, length, (a, b) -> comparator.compare(input[a], input[b])); - } - - /** - * Perform a recursive, descending merge sort. - * - * @param fromIndex inclusive - * @param toIndex exclusive - */ - private static void topDownMergeSort( - int[] src, int[] dst, int fromIndex, int toIndex, IntBinaryOperator comp) { - if (toIndex - fromIndex <= MIN_LENGTH_FOR_INSERTION_SORT) { - insertionSort(fromIndex, toIndex - fromIndex, dst, comp); - return; - } - - final int mid = (fromIndex + toIndex) >>> 1; - topDownMergeSort(dst, src, fromIndex, mid, comp); - topDownMergeSort(dst, src, mid, toIndex, comp); - - /* - * Both splits in of src are now sorted. - */ - if (comp.applyAsInt(src[mid - 1], src[mid]) <= 0) { - /* - * If the lowest element in upper slice is larger than the highest element in - * the lower slice, simply copy over, the data is fully sorted. - */ - System.arraycopy(src, fromIndex, dst, fromIndex, toIndex - fromIndex); - } else { - /* - * Run a manual merge. - */ - for (int i = fromIndex, j = mid, k = fromIndex; k < toIndex; k++) { - if (j == toIndex || (i < mid && comp.applyAsInt(src[i], src[j]) <= 0)) { - dst[k] = src[i++]; - } else { - dst[k] = src[j++]; - } - } - } - } - - /** Internal insertion sort for ints. */ - private static void insertionSort( - final int off, final int len, int[] order, IntBinaryOperator intComparator) { - for (int i = off + 1; i < off + len; i++) { - final int v = order[i]; - int j = i, t; - while (j > off && intComparator.applyAsInt(t = order[j - 1], v) > 0) { - order[j--] = t; - } - order[j] = v; - } - } - - /** Creates the initial order array. */ - private static int[] createOrderArray(final int start, final int length) { - final int[] order = new int[length]; - for (int i = 0; i < length; i++) { - order[i] = start + i; - } - return order; - } -} diff --git a/sources/main/java/com/carrotsearch/hppc/sorting/QuickSort.java b/sources/main/java/com/carrotsearch/hppc/sorting/QuickSort.java deleted file mode 100644 index b547dc68..00000000 --- a/sources/main/java/com/carrotsearch/hppc/sorting/QuickSort.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * HPPC - * - * Copyright (C) 2010-2024 Carrot Search s.c. and contributors - * All rights reserved. - * - * Refer to the full license file "LICENSE.txt": - * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt - */ -package com.carrotsearch.hppc.sorting; - -import java.util.function.IntBinaryOperator; - -/** - * In-place Quick sort with 3-way partitioning and ending with Insertion sort. - * - *

The sorting is not stable. Performance is O(n.log(n)) and memory is O(1) (although recursion - * memory is O(log(n))). - */ -public final class QuickSort { - - /** Below this size threshold, the sub-range is sorted using Insertion sort. */ - static final int INSERTION_SORT_THRESHOLD = 16; - - /** /** Below this size threshold, the partition selection is simplified to a single median. */ - static final int SINGLE_MEDIAN_THRESHOLD = 40; - - /** No instantiation. */ - private QuickSort() { - // No instantiation. - } - - /** - * @see #sort(int, int, IntBinaryOperator, IntBinaryOperator) - */ - public static void sort(int[] array, IntBinaryOperator comparator) { - sort(array, 0, array.length, comparator); - } - - /** - * @see #sort(int, int, IntBinaryOperator, IntBinaryOperator) - */ - public static void sort(int[] array, int fromIndex, int toIndex, IntBinaryOperator comparator) { - sort( - fromIndex, - toIndex, - comparator, - (i, j) -> { - int swap = array[i]; - array[i] = array[j]; - array[j] = swap; - return 0; - }); - } - - /** - * Performs a recursive in-place Quick sort. The sorting is not stable. - * - * @param fromIndex Index where to start sorting in the array, inclusive. - * @param toIndex Index where to stop sorting in the array, exclusive. - * @param comparator Compares elements based on their indices. Given indices i and j in the - * provided array, this comparator returns respectively -1/0/1 if the element at index i is - * respectively less/equal/greater than the element at index j. - * @param swapper Swaps the elements in the array at the given indices. For example, a custom - * swapper may allow sorting two arrays simultaneously. - */ - public static void sort( - int fromIndex, int toIndex, IntBinaryOperator comparator, IntBinaryOperator swapper) { - int size; - while ((size = toIndex - fromIndex) > INSERTION_SORT_THRESHOLD) { - - // Pivot selection. - int last = toIndex - 1; - int middle = (fromIndex + last) >>> 1; - int pivot; - if (size <= SINGLE_MEDIAN_THRESHOLD) { - // Select the pivot with a single median around the middle element. - // Do not take the median between [from, mid, last] because it hurts performance - // if the order is descending. - int range = size >> 2; - pivot = median(middle - range, middle, middle + range, comparator); - } else { - // Select the pivot with the median of medians. - int range = size >> 3; - int doubleRange = range << 1; - int medianStart = median(fromIndex, fromIndex + range, fromIndex + doubleRange, comparator); - int medianMiddle = median(middle - range, middle, middle + range, comparator); - int medianEnd = median(last - doubleRange, last - range, last, comparator); - pivot = median(medianStart, medianMiddle, medianEnd, comparator); - } - - // Bentley-McIlroy 3-way partitioning. - swap(fromIndex, pivot, swapper); - int i = fromIndex; - int j = toIndex; - int p = fromIndex + 1; - int q = last; - while (true) { - int leftCmp, rightCmp; - while ((leftCmp = compare(++i, fromIndex, comparator)) < 0) { - // repeat - } - while ((rightCmp = compare(--j, fromIndex, comparator)) > 0) { - // repeat - } - if (i >= j) { - if (i == j && rightCmp == 0) { - swap(i, p, swapper); - } - break; - } - swap(i, j, swapper); - if (rightCmp == 0) { - swap(i, p++, swapper); - } - if (leftCmp == 0) { - swap(j, q--, swapper); - } - } - i = j + 1; - for (int k = fromIndex; k < p; ) { - swap(k++, j--, swapper); - } - for (int k = last; k > q; ) { - swap(k--, i++, swapper); - } - - // Recursion on the smallest partition. - // Replace the tail recursion by a loop. - if (j - fromIndex < last - i) { - sort(fromIndex, j + 1, comparator, swapper); - fromIndex = i; - } else { - sort(i, toIndex, comparator, swapper); - toIndex = j + 1; - } - } - - insertionSort(fromIndex, toIndex, comparator, swapper); - } - - /** Sorts between from (inclusive) and to (exclusive) with insertion sort. */ - private static void insertionSort( - int fromIndex, int toIndex, IntBinaryOperator comparator, IntBinaryOperator swapper) { - for (int i = fromIndex + 1; i < toIndex; ) { - int current = i++; - int previous; - while (compare((previous = current - 1), current, comparator) > 0) { - swap(previous, current, swapper); - if (previous == fromIndex) { - break; - } - current = previous; - } - } - } - - /** Returns the index of the median element among three elements at provided indices. */ - private static int median(int i, int j, int k, IntBinaryOperator comparator) { - if (compare(i, j, comparator) < 0) { - if (compare(j, k, comparator) <= 0) { - return j; - } - return compare(i, k, comparator) < 0 ? k : i; - } - if (compare(j, k, comparator) >= 0) { - return j; - } - return compare(i, k, comparator) < 0 ? i : k; - } - - /** Compares two elements at provided indices. */ - private static int compare(int i, int j, IntBinaryOperator comparator) { - return comparator.applyAsInt(i, j); - } - - /** Swaps two elements at provided indices. */ - private static void swap(int i, int j, IntBinaryOperator swapper) { - swapper.applyAsInt(i, j); - } -} diff --git a/sources/main/java/javax/annotation/CheckForNull.java b/sources/main/java/javax/annotation/CheckForNull.java deleted file mode 100644 index 9573a166..00000000 --- a/sources/main/java/javax/annotation/CheckForNull.java +++ /dev/null @@ -1,23 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifierNickname; -import javax.annotation.meta.When; - -/** - * The annotated element might be null, and uses of the element should check for - * null. - *

- * When this annotation is applied to a method it applies to the method return - * value. - */ -@Documented -@TypeQualifierNickname -@Nonnull(when = When.MAYBE) -@Retention(RetentionPolicy.RUNTIME) -public @interface CheckForNull { - -} diff --git a/sources/main/java/javax/annotation/CheckForSigned.java b/sources/main/java/javax/annotation/CheckForSigned.java deleted file mode 100644 index 4edafaab..00000000 --- a/sources/main/java/javax/annotation/CheckForSigned.java +++ /dev/null @@ -1,22 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifierNickname; -import javax.annotation.meta.When; - -/** - * Used to annotate a value that may be either negative or nonnegative, and - * indicates that uses of it should check for negative values before using it in - * a way that requires the value to be nonnegative, and check for it being - * nonnegative before using it in a way that requires it to be negative. - */ -@Documented -@TypeQualifierNickname -@Nonnegative(when = When.MAYBE) -@Retention(RetentionPolicy.RUNTIME) -public @interface CheckForSigned { - -} diff --git a/sources/main/java/javax/annotation/CheckReturnValue.java b/sources/main/java/javax/annotation/CheckReturnValue.java deleted file mode 100644 index d28cf745..00000000 --- a/sources/main/java/javax/annotation/CheckReturnValue.java +++ /dev/null @@ -1,20 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import javax.annotation.meta.When; - -/** - * This annotation is used to denote a method whose return value should always - * be checked after invoking the method. - */ -@Documented -@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.PACKAGE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface CheckReturnValue { - When when() default When.ALWAYS; -} diff --git a/sources/main/java/javax/annotation/Detainted.java b/sources/main/java/javax/annotation/Detainted.java deleted file mode 100644 index d8620f2f..00000000 --- a/sources/main/java/javax/annotation/Detainted.java +++ /dev/null @@ -1,16 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifierNickname; -import javax.annotation.meta.When; - -@Documented -@TypeQualifierNickname -@Untainted(when = When.ALWAYS) -@Retention(RetentionPolicy.RUNTIME) -public @interface Detainted { - -} diff --git a/sources/main/java/javax/annotation/Generated.java b/sources/main/java/javax/annotation/Generated.java deleted file mode 100644 index 0db0dbbe..00000000 --- a/sources/main/java/javax/annotation/Generated.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * The Generated annotation is used to mark source code that has - * been generated. It can also be used to differentiate user written code from - * generated code in a single file. - *

- * The value element must have the name of the code generator. The - * recommended convention is to use the fully qualified name of the code - * generator in the value field, for example - * com.company.package.classname. - *

- *

- * The date element is used to indicate the date the source was - * generated. The date element must follow the ISO 8601 standard. - * For example, the date element could have the value - * 2001-07-04T12:08:56.235-0700, which represents 2001-07-04 - * 12:08:56 local time in the U.S. Pacific time zone. - *

- *

- * The comment element is a place holder for any comments that the - * code generator may want to include in the generated code. - *

- * - * @since 1.6, Common Annotations 1.0 - */ - -@Documented -@Retention(SOURCE) -@Target({ PACKAGE, TYPE, ANNOTATION_TYPE, METHOD, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, PARAMETER }) -public @interface Generated { - /** - * The value element must have the name of the code generator. The recommended - * convention is to use the fully qualified name of the code generator. For - * example: com.acme.generator.CodeGen. - */ - String[] value(); - - /** - * Date when the source was generated. - */ - String date() default ""; - - /** - * A place holder for any comments that the code generator may want to include - * in the generated code. - */ - String comments() default ""; -} diff --git a/sources/main/java/javax/annotation/ManagedBean.java b/sources/main/java/javax/annotation/ManagedBean.java deleted file mode 100644 index d50a9c25..00000000 --- a/sources/main/java/javax/annotation/ManagedBean.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2009-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * The ManagedBean annotation marks a POJO (Plain Old Java Object) - * as a ManagedBean. A ManagedBean supports a small set of basic services such - * as resource injection, lifecycle callbacks and interceptors. - * - * @since Common Annotations 1.1 - */ -@Target(TYPE) -@Retention(RUNTIME) -public @interface ManagedBean { - /** - * The name of the Managed Bean. Managed Bean names must be unique within a Java - * EE module. For each named Managed Bean, Java EE containers must make - * available the following entries in JNDI, using the same naming scheme used - * for EJB components. - *

- * In the application namespace: - *

- * java:app/<module-name>/<bean-name> - *

- * In the module namespace of the module containing the Managed Bean: - *

- * java:module/<bean-name> - * - */ - public String value() default ""; -} diff --git a/sources/main/java/javax/annotation/MatchesPattern.java b/sources/main/java/javax/annotation/MatchesPattern.java deleted file mode 100644 index 8428e64f..00000000 --- a/sources/main/java/javax/annotation/MatchesPattern.java +++ /dev/null @@ -1,37 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.regex.Pattern; - -import javax.annotation.meta.TypeQualifier; -import javax.annotation.meta.TypeQualifierValidator; -import javax.annotation.meta.When; - -/** - * This annotation is used to denote String values that should always match - * given pattern. - *

- * When this annotation is applied to a method it applies to the method return - * value. - */ -@Documented -@TypeQualifier(applicableTo = String.class) -@Retention(RetentionPolicy.RUNTIME) -public @interface MatchesPattern { - @RegEx - String value(); - - int flags() default 0; - - static class Checker implements TypeQualifierValidator { - public When forConstantValue(MatchesPattern annotation, Object value) { - Pattern p = Pattern.compile(annotation.value(), annotation.flags()); - if (p.matcher(((String) value)).matches()) - return When.ALWAYS; - return When.NEVER; - } - - } -} diff --git a/sources/main/java/javax/annotation/Nonnegative.java b/sources/main/java/javax/annotation/Nonnegative.java deleted file mode 100644 index 7e3eefaa..00000000 --- a/sources/main/java/javax/annotation/Nonnegative.java +++ /dev/null @@ -1,47 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifier; -import javax.annotation.meta.TypeQualifierValidator; -import javax.annotation.meta.When; - -/** - * This annotation is used to annotate a value that should only contain - * nonnegative values. - *

- * When this annotation is applied to a method it applies to the method return - * value. - */ -@Documented -@TypeQualifier(applicableTo = Number.class) -@Retention(RetentionPolicy.RUNTIME) -public @interface Nonnegative { - When when() default When.ALWAYS; - - class Checker implements TypeQualifierValidator { - - public When forConstantValue(Nonnegative annotation, Object v) { - if (!(v instanceof Number)) - return When.NEVER; - boolean isNegative; - Number value = (Number) v; - if (value instanceof Long) - isNegative = value.longValue() < 0; - else if (value instanceof Double) - isNegative = value.doubleValue() < 0; - else if (value instanceof Float) - isNegative = value.floatValue() < 0; - else - isNegative = value.intValue() < 0; - - if (isNegative) - return When.NEVER; - else - return When.ALWAYS; - - } - } -} diff --git a/sources/main/java/javax/annotation/Nonnull.java b/sources/main/java/javax/annotation/Nonnull.java deleted file mode 100644 index 04d1bbe8..00000000 --- a/sources/main/java/javax/annotation/Nonnull.java +++ /dev/null @@ -1,33 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifier; -import javax.annotation.meta.TypeQualifierValidator; -import javax.annotation.meta.When; - -/** - * The annotated element must not be null. - *

- * Annotated fields must not be null after construction has completed. - *

- * When this annotation is applied to a method it applies to the method return - * value. - */ -@Documented -@TypeQualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface Nonnull { - When when() default When.ALWAYS; - - class Checker implements TypeQualifierValidator { - - public When forConstantValue(Nonnull qualifierArgument, Object value) { - if (value == null) - return When.NEVER; - return When.ALWAYS; - } - } -} diff --git a/sources/main/java/javax/annotation/Nullable.java b/sources/main/java/javax/annotation/Nullable.java deleted file mode 100644 index ae2bf4f5..00000000 --- a/sources/main/java/javax/annotation/Nullable.java +++ /dev/null @@ -1,32 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifierNickname; -import javax.annotation.meta.When; - -/** - * The annotated element could be null under some circumstances. - *

- * In general, this means developers will have to read the documentation to - * determine when a null value is acceptable and whether it is necessary to - * check for a null value. - *

- * This annotation is useful mostly for overriding a {@link Nonnull} annotation. - * Static analysis tools should generally treat the annotated items as though - * they had no annotation, unless they are configured to minimize false - * negatives. Use {@link CheckForNull} to indicate that the element value should - * always be checked for a null value. - *

- * When this annotation is applied to a method it applies to the method return - * value. - */ -@Documented -@TypeQualifierNickname -@Nonnull(when = When.UNKNOWN) -@Retention(RetentionPolicy.RUNTIME) -public @interface Nullable { - -} diff --git a/sources/main/java/javax/annotation/OverridingMethodsMustInvokeSuper.java b/sources/main/java/javax/annotation/OverridingMethodsMustInvokeSuper.java deleted file mode 100644 index bb922583..00000000 --- a/sources/main/java/javax/annotation/OverridingMethodsMustInvokeSuper.java +++ /dev/null @@ -1,21 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * When this annotation is applied to a method, it indicates that if this method - * is overridden in a subclass, the overriding method should invoke this method - * (through method invocation on super). - *

- * An example of such method is {@link Object#finalize()}. - */ -@Documented -@Target({ ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface OverridingMethodsMustInvokeSuper { - -} diff --git a/sources/main/java/javax/annotation/ParametersAreNonnullByDefault.java b/sources/main/java/javax/annotation/ParametersAreNonnullByDefault.java deleted file mode 100644 index 0b4f61de..00000000 --- a/sources/main/java/javax/annotation/ParametersAreNonnullByDefault.java +++ /dev/null @@ -1,29 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifierDefault; - -/** - * This annotation can be applied to a package, class or method to indicate that - * the method parameters in that element are nonnull by default unless there is: - *

    - *
  • An explicit nullness annotation - *
  • The method overrides a method in a superclass (in which case the - * annotation of the corresponding parameter in the superclass applies) - *
  • There is a default parameter annotation (like - * {@link ParametersAreNullableByDefault}) applied to a more tightly nested - * element. - *
- * - * @see Nonnull - */ -@Documented -@Nonnull -@TypeQualifierDefault(ElementType.PARAMETER) -@Retention(RetentionPolicy.RUNTIME) -public @interface ParametersAreNonnullByDefault { -} diff --git a/sources/main/java/javax/annotation/ParametersAreNullableByDefault.java b/sources/main/java/javax/annotation/ParametersAreNullableByDefault.java deleted file mode 100644 index 933e9864..00000000 --- a/sources/main/java/javax/annotation/ParametersAreNullableByDefault.java +++ /dev/null @@ -1,33 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifierDefault; - -/** - * This annotation can be applied to a package, class or method to indicate that - * the method parameters in that element are nullable by default unless there - * is: - *
    - *
  • An explicit nullness annotation - *
  • The method overrides a method in a superclass (in which case the - * annotation of the corresponding parameter in the superclass applies) - *
  • There is a default parameter annotation applied to a more tightly nested - * element. - *
- *

- * This annotation implies the same "nullness" as no annotation. However, it is - * different than having no annotation, as it is inherited and it can override a - * {@link ParametersAreNonnullByDefault} annotation at an outer scope. - * - * @see Nullable - */ -@Documented -@Nullable -@TypeQualifierDefault(ElementType.PARAMETER) -@Retention(RetentionPolicy.RUNTIME) -public @interface ParametersAreNullableByDefault { -} diff --git a/sources/main/java/javax/annotation/PostConstruct.java b/sources/main/java/javax/annotation/PostConstruct.java deleted file mode 100644 index 92388c90..00000000 --- a/sources/main/java/javax/annotation/PostConstruct.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * The PostConstruct annotation is used on a method that needs to - * be executed after dependency injection is done to perform any initialization. - * This method must be invoked before the class is put into service. This - * annotation must be supported on all classes that support dependency - * injection. The method annotated with PostConstruct must be - * invoked even if the class does not request any resources to be injected. Only - * one method in a given class can be annotated with this annotation. The method - * on which the PostConstruct annotation is applied must fulfill - * all of the following criteria: - *

    - *
  • The method must not have any parameters except in the case of - * interceptors in which case it takes an InvocationContext object - * as defined by the Interceptors specification.
  • - *
  • The method defined on an interceptor class or superclass of an - * interceptor class must have one of the following signatures: - *

    - * void <METHOD>(InvocationContext) - *

    - * Object <METHOD>(InvocationContext) throws Exception - *

    - * Note: A PostConstruct interceptor method must not throw application - * exceptions, but it may be declared to throw checked exceptions including the - * java.lang.Exception if the same interceptor method interposes on business or - * timeout methods in addition to lifecycle events. If a PostConstruct - * interceptor method returns a value, it is ignored by the container.

  • - *
  • The method defined on a non-interceptor class must have the following - * signature: - *

    - * void <METHOD>()

  • - *
  • The method on which the PostConstruct annotation is applied - * may be public, protected, package private or private.
  • - *
  • The method must not be static except for the application client.
  • - *
  • The method should not be final.
  • - *
  • If the method throws an unchecked exception the class must not be put - * into service except in the case where the exception is handled by an - * interceptor.
  • - *
- * - * @see javax.annotation.PreDestroy - * @see javax.annotation.Resource - * @since 1.6, Common Annotations 1.0 - */ -@Documented -@Retention(RUNTIME) -@Target(METHOD) -public @interface PostConstruct { -} diff --git a/sources/main/java/javax/annotation/PreDestroy.java b/sources/main/java/javax/annotation/PreDestroy.java deleted file mode 100644 index d8a38582..00000000 --- a/sources/main/java/javax/annotation/PreDestroy.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * The PreDestroy annotation is used on a method as a callback - * notification to signal that the instance is in the process of being removed - * by the container. The method annotated with PreDestroy is - * typically used to release resources that it has been holding. This annotation - * must be supported by all container-managed objects that support the use of - * the PostConstruct annotation except the Java EE application - * client. The method on which the PreDestroy annotation is applied - * must fulfill all of the following criteria: - *
    - *
  • The method must not have any parameters except in the case of - * interceptors in which case it takes an InvocationContext object - * as defined by the Interceptors specification.
  • - *
  • The method defined on an interceptor class or superclass of an - * interceptor class must have one of the following signatures: - *

    - * void <METHOD>(InvocationContext) - *

    - * Object <METHOD>(InvocationContext) throws Exception - *

    - * Note: A PreDestroy interceptor method must not throw application - * exceptions, but it may be declared to throw checked exceptions including the - * java.lang.Exception if the same interceptor method interposes on business or - * timeout methods in addition to lifecycle events. If a PreDestroy interceptor - * method returns a value, it is ignored by the container.

  • - *
  • The method defined on a non-interceptor class must have the following - * signature: - *

    - * void <METHOD>()

  • - *
  • The method on which PreDestroy is applied may be public, protected, - * package private or private.
  • - *
  • The method must not be static.
  • - *
  • The method should not be final.
  • - *
  • If the method throws an unchecked exception it is ignored by the - * container.
  • - *
- * - * @see javax.annotation.PostConstruct - * @see javax.annotation.Resource - * @since 1.6, Common Annotations 1.0 - */ - -@Documented -@Retention(RUNTIME) -@Target(METHOD) -public @interface PreDestroy { -} diff --git a/sources/main/java/javax/annotation/Priority.java b/sources/main/java/javax/annotation/Priority.java deleted file mode 100644 index 35d37b55..00000000 --- a/sources/main/java/javax/annotation/Priority.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation; - -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * The Priority annotation can be applied to classes or parameters - * to indicate in what order they should be used. The effect of using the - * Priority annotation in any particular instance is defined by - * other specifications that define the use of a specific class. - *

- * For example, the Interceptors specification defines the use of priorities on - * interceptors to control the order in which interceptors are called. - *

- *

- * Priority values should generally be non-negative, with negative values - * reserved for special meanings such as "undefined" or "not specified". A - * specification that defines use of the Priority annotation may - * define the range of allowed priorities and any priority values with special - * meaning. - *

- * - * @since Common Annotations 1.2 - */ -@Target({ TYPE, PARAMETER }) -@Retention(RUNTIME) -@Documented -public @interface Priority { - /** - * The priority value. - */ - int value(); -} diff --git a/sources/main/java/javax/annotation/PropertyKey.java b/sources/main/java/javax/annotation/PropertyKey.java deleted file mode 100644 index d2a6cd48..00000000 --- a/sources/main/java/javax/annotation/PropertyKey.java +++ /dev/null @@ -1,15 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifier; -import javax.annotation.meta.When; - -@Documented -@TypeQualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface PropertyKey { - When when() default When.ALWAYS; -} diff --git a/sources/main/java/javax/annotation/RegEx.java b/sources/main/java/javax/annotation/RegEx.java deleted file mode 100644 index a04b7bab..00000000 --- a/sources/main/java/javax/annotation/RegEx.java +++ /dev/null @@ -1,44 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import javax.annotation.meta.TypeQualifierNickname; -import javax.annotation.meta.TypeQualifierValidator; -import javax.annotation.meta.When; - -/** - * This qualifier is used to denote String values that should be a Regular - * expression. - *

- * When this annotation is applied to a method it applies to the method return - * value. - */ -@Documented -@Syntax("RegEx") -@TypeQualifierNickname -@Retention(RetentionPolicy.RUNTIME) -public @interface RegEx { - When when() default When.ALWAYS; - - static class Checker implements TypeQualifierValidator { - - public When forConstantValue(RegEx annotation, Object value) { - if (!(value instanceof String)) - return When.NEVER; - - try { - Pattern.compile((String) value); - } catch (PatternSyntaxException e) { - return When.NEVER; - } - return When.ALWAYS; - - } - - } - -} diff --git a/sources/main/java/javax/annotation/Resource.java b/sources/main/java/javax/annotation/Resource.java deleted file mode 100644 index b6e8f5f3..00000000 --- a/sources/main/java/javax/annotation/Resource.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * The Resource annotation marks a resource that is needed by the - * application. This annotation may be applied to an application component - * class, or to fields or methods of the component class. When the annotation is - * applied to a field or method, the container will inject an instance of the - * requested resource into the application component when the component is - * initialized. If the annotation is applied to the component class, the - * annotation declares a resource that the application will look up at runtime. - *

- * Even though this annotation is not marked Inherited, deployment - * tools are required to examine all superclasses of any component class to - * discover all uses of this annotation in all superclasses. All such annotation - * instances specify resources that are needed by the application component. - * Note that this annotation may appear on private fields and methods of - * superclasses; the container is required to perform injection in these cases - * as well. - *

- * - * @since 1.6, Common Annotations 1.0 - */ -@Target({ TYPE, FIELD, METHOD }) -@Retention(RUNTIME) -@Repeatable(Resources.class) -public @interface Resource { - /** - * The JNDI name of the resource. For field annotations, the default is the - * field name. For method annotations, the default is the JavaBeans property - * name corresponding to the method. For class annotations, there is no default - * and this must be specified. - */ - String name() default ""; - - /** - * The name of the resource that the reference points to. It can link to any - * compatible resource using the global JNDI names. - * - * @since 1.7, Common Annotations 1.1 - */ - - String lookup() default ""; - - /** - * The Java type of the resource. For field annotations, the default is the type - * of the field. For method annotations, the default is the type of the - * JavaBeans property. For class annotations, there is no default and this must - * be specified. - */ - Class type() default java.lang.Object.class; - - /** - * The two possible authentication types for a resource. - */ - enum AuthenticationType { - CONTAINER, APPLICATION - } - - /** - * The authentication type to use for this resource. This may be specified for - * resources representing a connection factory of any supported type, and must - * not be specified for resources of other types. - */ - AuthenticationType authenticationType() default AuthenticationType.CONTAINER; - - /** - * Indicates whether this resource can be shared between this component and - * other components. This may be specified for resources representing a - * connection factory of any supported type, and must not be specified for - * resources of other types. - */ - boolean shareable() default true; - - /** - * A product-specific name that this resource should be mapped to. The - * mappedName element provides for mapping the resource reference - * to the name of a resource known to the applicaiton server. The mapped name - * could be of any form. - *

- * Application servers are not required to support any particular form or type - * of mapped name, nor the ability to use mapped names. The mapped name is - * product-dependent and often installation-dependent. No use of a mapped name - * is portable. - *

- */ - String mappedName() default ""; - - /** - * Description of this resource. The description is expected to be in the - * default language of the system on which the application is deployed. The - * description can be presented to the Deployer to help in choosing the correct - * resource. - */ - String description() default ""; -} diff --git a/sources/main/java/javax/annotation/Resources.java b/sources/main/java/javax/annotation/Resources.java deleted file mode 100644 index 2950ef54..00000000 --- a/sources/main/java/javax/annotation/Resources.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * This class is used to allow multiple resources declarations. - * - * @see javax.annotation.Resource - * @since 1.6, Common Annotations 1.0 - */ - -@Documented -@Retention(RUNTIME) -@Target(TYPE) -public @interface Resources { - /** - * Array used for multiple resource declarations. - */ - Resource[] value(); -} diff --git a/sources/main/java/javax/annotation/Signed.java b/sources/main/java/javax/annotation/Signed.java deleted file mode 100644 index d8cf61c2..00000000 --- a/sources/main/java/javax/annotation/Signed.java +++ /dev/null @@ -1,19 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifierNickname; -import javax.annotation.meta.When; - -/** - * Used to annotate a value of unknown sign. - */ -@Documented -@TypeQualifierNickname -@Nonnegative(when = When.UNKNOWN) -@Retention(RetentionPolicy.RUNTIME) -public @interface Signed { - -} diff --git a/sources/main/java/javax/annotation/Syntax.java b/sources/main/java/javax/annotation/Syntax.java deleted file mode 100644 index fea56243..00000000 --- a/sources/main/java/javax/annotation/Syntax.java +++ /dev/null @@ -1,45 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifier; -import javax.annotation.meta.When; - -/** - * This annotation a value that is of a particular syntax, such as Java syntax - * or regular expression syntax. This can be used to provide syntax checking of - * constant values at compile time, run time checking at runtime, and can assist - * IDEs in deciding how to interpret String constants (e.g., should a - * refactoring that renames method {@code x()} to {@code y()} update the String - * constant {@code "x()"}). - */ -@Documented -@TypeQualifier(applicableTo = CharSequence.class) -@Retention(RetentionPolicy.RUNTIME) -public @interface Syntax { - /** - * Value indicating the particular syntax denoted by this annotation. Different - * tools will recognize different syntaxes, but some proposed canonical values - * are: - *
    - *
  • "Java" - *
  • "RegEx" - *
  • "JavaScript" - *
  • "Ruby" - *
  • "Groovy" - *
  • "SQL" - *
  • "FormatString" - *
- *

- * Syntax names can be followed by a colon and a list of key value pairs, - * separated by commas. For example, "SQL:dialect=Oracle,version=2.3". Tools - * should ignore any keys they don't recognize. - * - * @return a name indicating the particular syntax. - */ - String value(); - - When when() default When.ALWAYS; -} diff --git a/sources/main/java/javax/annotation/Tainted.java b/sources/main/java/javax/annotation/Tainted.java deleted file mode 100644 index 7a90ad0d..00000000 --- a/sources/main/java/javax/annotation/Tainted.java +++ /dev/null @@ -1,28 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifierNickname; -import javax.annotation.meta.When; - -/** - * This annotation is used to denote String values that are tainted, i.e. may - * come from untrusted sources without proper validation. - *

- * For example, this annotation should be used on the String value which - * represents raw input received from the web form. - *

- * When this annotation is applied to a method it applies to the method return - * value. - * - * @see Untainted - */ -@Documented -@TypeQualifierNickname -@Untainted(when = When.MAYBE) -@Retention(RetentionPolicy.RUNTIME) -public @interface Tainted { - -} diff --git a/sources/main/java/javax/annotation/Untainted.java b/sources/main/java/javax/annotation/Untainted.java deleted file mode 100644 index 22e8b101..00000000 --- a/sources/main/java/javax/annotation/Untainted.java +++ /dev/null @@ -1,27 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.annotation.meta.TypeQualifier; -import javax.annotation.meta.When; - -/** - * This annotation is used to denote String values that are untainted, i.e. - * properly validated. - *

- * For example, this annotation should be used on the String value which - * represents SQL query to be passed to database engine. - *

- * When this annotation is applied to a method it applies to the method return - * value. - * - * @see Tainted - */ -@Documented -@TypeQualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface Untainted { - When when() default When.ALWAYS; -} diff --git a/sources/main/java/javax/annotation/WillClose.java b/sources/main/java/javax/annotation/WillClose.java deleted file mode 100644 index 82344f10..00000000 --- a/sources/main/java/javax/annotation/WillClose.java +++ /dev/null @@ -1,18 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Used to annotate a method parameter to indicate that this method will close - * the resource. - * - * @see WillCloseWhenClosed - * @see WillNotClose - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface WillClose { - -} diff --git a/sources/main/java/javax/annotation/WillCloseWhenClosed.java b/sources/main/java/javax/annotation/WillCloseWhenClosed.java deleted file mode 100644 index d67ae4f4..00000000 --- a/sources/main/java/javax/annotation/WillCloseWhenClosed.java +++ /dev/null @@ -1,18 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Used to annotate a constructor/factory parameter to indicate that returned - * object (X) will close the resource when X is closed. - * - * @see WillClose - * @see WillNotClose - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface WillCloseWhenClosed { - -} diff --git a/sources/main/java/javax/annotation/WillNotClose.java b/sources/main/java/javax/annotation/WillNotClose.java deleted file mode 100644 index 4145fab2..00000000 --- a/sources/main/java/javax/annotation/WillNotClose.java +++ /dev/null @@ -1,18 +0,0 @@ -package javax.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Used to annotate a method parameter to indicate that this method will not - * close the resource. - * - * @see WillClose - * @see WillCloseWhenClosed - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface WillNotClose { - -} diff --git a/sources/main/java/javax/annotation/concurrent/GuardedBy.java b/sources/main/java/javax/annotation/concurrent/GuardedBy.java deleted file mode 100644 index d3df157f..00000000 --- a/sources/main/java/javax/annotation/concurrent/GuardedBy.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2005 Brian Goetz - * Released under the Creative Commons Attribution License - * (http://creativecommons.org/licenses/by/2.5) - * Official home: http://www.jcip.net - */ -package javax.annotation.concurrent; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * The field or method to which this annotation is applied can only be accessed - * when holding a particular lock, which may be a built-in (synchronization) - * lock, or may be an explicit {@link java.util.concurrent.locks.Lock}. - *

- * The argument determines which lock guards the annotated field or method: - *

    - *
  • this : The string literal "this" means that this field is guarded by the - * class in which it is defined. - *
  • class-name.this : For inner classes, it may be necessary to disambiguate - * 'this'; the class-name.this designation allows you to specify which 'this' - * reference is intended - *
  • itself : For reference fields only; the object to which the field refers. - *
  • field-name : The lock object is referenced by the (instance or static) - * field specified by field-name. - *
  • class-name.field-name : The lock object is reference by the static field - * specified by class-name.field-name. - *
  • method-name() : The lock object is returned by calling the named nil-ary - * method. - *
  • class-name.class : The Class object for the specified class should be - * used as the lock object. - *
- */ -@Target({ ElementType.FIELD, ElementType.METHOD }) -@Retention(RetentionPolicy.CLASS) -public @interface GuardedBy { - String value(); -} diff --git a/sources/main/java/javax/annotation/concurrent/Immutable.java b/sources/main/java/javax/annotation/concurrent/Immutable.java deleted file mode 100644 index 72bd98b3..00000000 --- a/sources/main/java/javax/annotation/concurrent/Immutable.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2005 Brian Goetz - * Released under the Creative Commons Attribution License - * (http://creativecommons.org/licenses/by/2.5) - * Official home: http://www.jcip.net - */ -package javax.annotation.concurrent; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * The class to which this annotation is applied is immutable. This means that - * its state cannot be seen to change by callers. Of necessity this means that - * all public fields are final, and that all public final reference fields refer - * to other immutable objects, and that methods do not publish references to any - * internal state which is mutable by implementation even if not by design. - * Immutable objects may still have internal mutable state for purposes of - * performance optimization; some state variables may be lazily computed, so - * long as they are computed from immutable state and that callers cannot tell - * the difference. - *

- * Immutable objects are inherently thread-safe; they may be passed between - * threads or published without synchronization. - */ -@Documented -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.CLASS) -public @interface Immutable { -} diff --git a/sources/main/java/javax/annotation/concurrent/NotThreadSafe.java b/sources/main/java/javax/annotation/concurrent/NotThreadSafe.java deleted file mode 100644 index 596f0b2f..00000000 --- a/sources/main/java/javax/annotation/concurrent/NotThreadSafe.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2005 Brian Goetz - * Released under the Creative Commons Attribution License - * (http://creativecommons.org/licenses/by/2.5) - * Official home: http://www.jcip.net - */ -package javax.annotation.concurrent; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * The class to which this annotation is applied is not thread-safe. This - * annotation primarily exists for clarifying the non-thread-safety of a class - * that might otherwise be assumed to be thread-safe, despite the fact that it - * is a bad idea to assume a class is thread-safe without good reason. - * - * @see ThreadSafe - */ -@Documented -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.CLASS) -public @interface NotThreadSafe { -} diff --git a/sources/main/java/javax/annotation/concurrent/ThreadSafe.java b/sources/main/java/javax/annotation/concurrent/ThreadSafe.java deleted file mode 100644 index 36d74365..00000000 --- a/sources/main/java/javax/annotation/concurrent/ThreadSafe.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2005 Brian Goetz - * Released under the Creative Commons Attribution License - * (http://creativecommons.org/licenses/by/2.5) - * Official home: http://www.jcip.net - */ -package javax.annotation.concurrent; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * The class to which this annotation is applied is thread-safe. This means that - * no sequences of accesses (reads and writes to public fields, calls to public - * methods) may put the object into an invalid state, regardless of the - * interleaving of those actions by the runtime, and without requiring any - * additional synchronization or coordination on the part of the caller. - * - * @see NotThreadSafe - */ -@Documented -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.CLASS) -public @interface ThreadSafe { -} diff --git a/sources/main/java/javax/annotation/meta/Exclusive.java b/sources/main/java/javax/annotation/meta/Exclusive.java deleted file mode 100644 index a9dae890..00000000 --- a/sources/main/java/javax/annotation/meta/Exclusive.java +++ /dev/null @@ -1,30 +0,0 @@ -package javax.annotation.meta; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * This annotation can be applied to the value() element of an annotation that - * is annotated as a TypeQualifier. - * - *

- * For example, the following defines a type qualifier such that if you know a - * value is {@literal @Foo(1)}, then the value cannot be {@literal @Foo(2)} or - * {{@literal @Foo(3)}. - * - *

- * @TypeQualifier
- * @interface Foo {
- * 	@Exclusive
- * 	int value();
- * }
- * 
- * - */ - -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface Exclusive { - -} diff --git a/sources/main/java/javax/annotation/meta/Exhaustive.java b/sources/main/java/javax/annotation/meta/Exhaustive.java deleted file mode 100644 index 9b1cb863..00000000 --- a/sources/main/java/javax/annotation/meta/Exhaustive.java +++ /dev/null @@ -1,40 +0,0 @@ -package javax.annotation.meta; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * This annotation can be applied to the value() element of an annotation that - * is annotated as a TypeQualifier. This is only appropriate if the value field - * returns a value that is an Enumeration. - * - *

- * Applications of the type qualifier with different values are exclusive, and - * the enumeration is an exhaustive list of the possible values. - * - *

- * For example, the following defines a type qualifier such that if you know a - * value is neither {@literal @Foo(Color.Red)} or {@literal @Foo(Color.Blue)}, - * then the value must be {@literal @Foo(Color.Green)}. And if you know it is - * {@literal @Foo(Color.Green)}, you know it cannot be - * {@literal @Foo(Color.Red)} or {@literal @Foo(Color.Blue)} - * - *

- * @TypeQualifier
- * @interface Foo {
- * 	enum Color {
- * 		RED, BLUE, GREEN
- * 	};
- * 
- * 	@Exhaustive
- * 	Color value();
- * }
- * 
- */ - -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface Exhaustive { - -} diff --git a/sources/main/java/javax/annotation/meta/TypeQualifier.java b/sources/main/java/javax/annotation/meta/TypeQualifier.java deleted file mode 100644 index 3d02b411..00000000 --- a/sources/main/java/javax/annotation/meta/TypeQualifier.java +++ /dev/null @@ -1,28 +0,0 @@ -package javax.annotation.meta; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This qualifier is applied to an annotation to denote that the annotation - * should be treated as a type qualifier. - */ -@Documented -@Target(ElementType.ANNOTATION_TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface TypeQualifier { - - /** - * Describes the kinds of values the qualifier can be applied to. If a numeric - * class is provided (e.g., Number.class or Integer.class) then the annotation - * can also be applied to the corresponding primitive numeric types. - * - * @return a class object which denotes the type of the values the original - * annotation can be applied to. - */ - Class applicableTo() default Object.class; - -} diff --git a/sources/main/java/javax/annotation/meta/TypeQualifierDefault.java b/sources/main/java/javax/annotation/meta/TypeQualifierDefault.java deleted file mode 100644 index d79dce8c..00000000 --- a/sources/main/java/javax/annotation/meta/TypeQualifierDefault.java +++ /dev/null @@ -1,20 +0,0 @@ -package javax.annotation.meta; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This qualifier is applied to an annotation to denote that the annotation - * defines a default type qualifier that is visible within the scope of the - * element it is applied to. - */ - -@Documented -@Target(ElementType.ANNOTATION_TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface TypeQualifierDefault { - ElementType[] value() default {}; -} diff --git a/sources/main/java/javax/annotation/meta/TypeQualifierNickname.java b/sources/main/java/javax/annotation/meta/TypeQualifierNickname.java deleted file mode 100644 index d24e271b..00000000 --- a/sources/main/java/javax/annotation/meta/TypeQualifierNickname.java +++ /dev/null @@ -1,30 +0,0 @@ -package javax.annotation.meta; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Target; - -/** - * This annotation is applied to a annotation, and marks the annotation as being - * a qualifier nickname. Applying a nickname annotation X to a element Y should - * be interpreted as having the same meaning as applying all of annotations of X - * (other than QualifierNickname) to Y. - * - *

- * Thus, you might define a qualifier SocialSecurityNumber as follows: - *

- * - *
- * @Documented
- * @TypeQualifierNickname
- * @Pattern("[0-9]{3}-[0-9]{2}-[0-9]{4}")
- * @Retention(RetentionPolicy.RUNTIME)
- * public @interface SocialSecurityNumber {
- * }
- * 
- */ -@Documented -@Target(ElementType.ANNOTATION_TYPE) -public @interface TypeQualifierNickname { - -} diff --git a/sources/main/java/javax/annotation/meta/TypeQualifierValidator.java b/sources/main/java/javax/annotation/meta/TypeQualifierValidator.java deleted file mode 100644 index 597f139a..00000000 --- a/sources/main/java/javax/annotation/meta/TypeQualifierValidator.java +++ /dev/null @@ -1,18 +0,0 @@ -package javax.annotation.meta; - -import java.lang.annotation.Annotation; - -import javax.annotation.Nonnull; - -public interface TypeQualifierValidator { - /** - * Given a type qualifier, check to see if a known specific constant value is an - * instance of the set of values denoted by the qualifier. - * - * @param annotation the type qualifier - * @param value the value to check - * @return a value indicating whether or not the value is an member of the - * values denoted by the type qualifier - */ - public @Nonnull When forConstantValue(@Nonnull A annotation, Object value); -} diff --git a/sources/main/java/javax/annotation/meta/When.java b/sources/main/java/javax/annotation/meta/When.java deleted file mode 100644 index 15faf384..00000000 --- a/sources/main/java/javax/annotation/meta/When.java +++ /dev/null @@ -1,23 +0,0 @@ -package javax.annotation.meta; - -/** - * Used to describe the relationship between a qualifier T and the set of values - * S possible on an annotated element. - * - * In particular, an issues should be reported if an ALWAYS or MAYBE value is - * used where a NEVER value is required, or if a NEVER or MAYBE value is used - * where an ALWAYS value is required. - * - * - */ -public enum When { - /** S is a subset of T */ - ALWAYS, - /** nothing definitive is known about the relation between S and T */ - UNKNOWN, - /** S intersection T is non empty and S - T is nonempty */ - MAYBE, - /** S intersection T is empty */ - NEVER; - -} diff --git a/sources/main/java/javax/annotation/package.html b/sources/main/java/javax/annotation/package.html deleted file mode 100644 index ccf7a00e..00000000 --- a/sources/main/java/javax/annotation/package.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - This package defines the common annotations. - - diff --git a/sources/main/java/javax/annotation/security/DeclareRoles.java b/sources/main/java/javax/annotation/security/DeclareRoles.java deleted file mode 100644 index 90cb4977..00000000 --- a/sources/main/java/javax/annotation/security/DeclareRoles.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation.security; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Used by application to declare security roles. It can be specified on a - * class. The value of the DeclareRoles annotation is a list of - * security role names. - * - * @since Common Annotations 1.0 - */ -@Documented -@Retention(RUNTIME) -@Target(TYPE) -public @interface DeclareRoles { - /** - * List of security role names. - */ - String[] value(); -} diff --git a/sources/main/java/javax/annotation/security/DenyAll.java b/sources/main/java/javax/annotation/security/DenyAll.java deleted file mode 100644 index d57a9658..00000000 --- a/sources/main/java/javax/annotation/security/DenyAll.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation.security; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Specifies that no security roles are allowed to invoke the specified - * method(s). - * - * @see javax.annotation.security.RolesAllowed - * @see javax.annotation.security.PermitAll - * @since Common Annotations 1.0 - */ -@Documented -@Retention(RUNTIME) -@Target({ TYPE, METHOD }) -public @interface DenyAll { -} diff --git a/sources/main/java/javax/annotation/security/PermitAll.java b/sources/main/java/javax/annotation/security/PermitAll.java deleted file mode 100644 index 5976eeec..00000000 --- a/sources/main/java/javax/annotation/security/PermitAll.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation.security; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Specifies that all security roles are allowed to invoke the specified - * method(s) — i.e., that the specified method(s) are "unchecked". It can - * be specified on a class or on methods. Specifying it on the class means that - * it applies to all methods of the class. If specified at the method level, it - * only affects that method. If the RolesAllowed annotation is - * specified at the class level and this annotation is applied at the method - * level, the PermitAll annotation overrides the - * RolesAllowed annotation for the specified method. - * - * @see javax.annotation.security.RolesAllowed - * @see javax.annotation.security.DenyAll - * - * @since Common Annotations 1.0 - */ -@Documented -@Retention(RUNTIME) -@Target({ TYPE, METHOD }) -public @interface PermitAll { -} diff --git a/sources/main/java/javax/annotation/security/RolesAllowed.java b/sources/main/java/javax/annotation/security/RolesAllowed.java deleted file mode 100644 index cdd876b4..00000000 --- a/sources/main/java/javax/annotation/security/RolesAllowed.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation.security; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Specifies the list of security roles permitted to access method(s) in an - * application. The value of the RolesAllowed annotation is a list - * of security role names. This annotation can be specified on a class or on - * method(s). Specifying it at a class level means that it applies to all the - * methods in the class. Specifying it on a method means that it is applicable - * to that method only. If applied at both the class and methods level, the - * method value overrides the class value if the two conflict. - * - * @since Common Annotations 1.0 - */ -@Documented -@Retention(RUNTIME) -@Target({ TYPE, METHOD }) -public @interface RolesAllowed { - /** - * List of roles that are permitted access. - */ - String[] value(); -} diff --git a/sources/main/java/javax/annotation/security/RunAs.java b/sources/main/java/javax/annotation/security/RunAs.java deleted file mode 100644 index 0f9d88c7..00000000 --- a/sources/main/java/javax/annotation/security/RunAs.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation.security; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Defines the identity of the application during execution. This allows - * developers to execute an application under a particular role. The role must - * map to the user / group information in the container's security realm. Its - * value is the name of a security role. - * - * @since Common Annotations 1.0 - */ -@Documented -@Retention(RUNTIME) -@Target(TYPE) -public @interface RunAs { - /** - * Name of a security role. - */ - String value(); -} diff --git a/sources/main/java/javax/annotation/security/package.html b/sources/main/java/javax/annotation/security/package.html deleted file mode 100644 index 5a195df8..00000000 --- a/sources/main/java/javax/annotation/security/package.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - This package contains the security common annotations. - - diff --git a/sources/main/java/javax/annotation/sql/DataSourceDefinition.java b/sources/main/java/javax/annotation/sql/DataSourceDefinition.java deleted file mode 100644 index dbda762a..00000000 --- a/sources/main/java/javax/annotation/sql/DataSourceDefinition.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2009-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation.sql; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation used to define a container DataSource to be - * registered with JNDI. The DataSource may be configured by - * setting the annotation elements for commonly used DataSource - * properties. Additional standard and vendor-specific properties may be - * specified using the properties element. - *

- * - * The data source will be registered under the name specified in the - * name element. It may be defined to be in any valid Java EE - * namespace, which will determine the accessibility of the data source from - * other components. - *

- * A JDBC driver implementation class of the appropriate type, either - * DataSource, ConnectionPoolDataSource, or - * XADataSource, must be indicated by the className - * element. The availability of the driver class will be assumed at runtime. - *

- * DataSource properties should not be specified more than once. If the url - * annotation element contains a DataSource property that was also specified - * using the corresponding annotation element or was specified in the properties - * annotation element, the precedence order is undefined and implementation - * specific: - *

- * - *

- *   @DataSourceDefinition(name="java:global/MyApp/MyDataSource",
- *      className="org.apache.derby.jdbc.ClientDataSource",
- *      url="jdbc:derby://localhost:1527/myDB;user=bill",
- *      user="lance",
- *      password="secret",
- *      databaseName="testDB",
- *      serverName="luckydog"
- *   )// DO NOT DO THIS!!!
- * 
- *

- * In the above example, the databaseName, user and - * serverName properties were specified as part of the - * url property and using the corresponding annotation elements. - * This should be avoided. - *

- * If the properties annotation element is used and contains a - * DataSource property that was also specified using the corresponding - * annotation element, the annotation element value takes precedence. For - * example: - *

- * - *

- *   @DataSourceDefinition(name="java:global/MyApp/MyDataSource",
- *      className="org.apache.derby.jdbc.ClientDataSource",
- *      user="lance",
- *      password="secret",
- *      databaseName="testDB",
- *      serverName="luckydog",
- *       properties= {"databaseName=myDB", "databaseProp=doThis"}
- *   )// DO NOT DO THIS!!!
- * 
- *

- * This would result in the following values being used when configuring the - * DataSource: - *

    - *
  • serverName=luckydog
  • - *
  • portNumber=1527
  • - *
  • databaseName=testDB
  • - *
  • user=lance
  • - *
  • password=secret
  • - *
  • databaseProp=doThis
  • - *
- *

- * Vendors are not required to support properties that do not normally apply to - * a specific data source type. For example, specifying the - * transactional property to be true but supplying a - * value for className that implements a data source class other - * than XADataSource may not be supported. - *

- * Vendor-specific properties may be combined with or used to override standard - * data source properties defined using this annotation. - *

- * DataSource properties that are specified and are not supported - * in a given configuration or cannot be mapped to a vendor specific - * configuration property may be ignored. - *

- * Examples:
- * - *

- *   @DataSourceDefinition(name="java:global/MyApp/MyDataSource",
- *      className="com.foobar.MyDataSource",
- *      portNumber=6689,
- *      serverName="myserver.com",
- *      user="lance",
- *      password="secret"
- *   )
- * 
- * 
- *

- * Using a URL:
- * - *

- *  @DataSourceDefinition(name="java:global/MyApp/MyDataSource",
- *    className="org.apache.derby.jdbc.ClientDataSource",
- *    url="jdbc:derby://localhost:1527/myDB",
- *    user="lance",
- *    password="secret"
- * )
- * 
- *

- * An example lookup of the DataSource from an EJB: - * - *

- * @Stateless
- * public class MyStatelessEJB {
- *   @Resource(lookup="java:global/MyApp/myDataSource")
- *    DataSource myDB;
- *      ...
- * }
- * 
- *

- * - * @see javax.sql.DataSource - * @see javax.sql.XADataSource - * @see javax.sql.ConnectionPoolDataSource - * @since Common Annotations 1.1 - */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Repeatable(DataSourceDefinitions.class) -public @interface DataSourceDefinition { - - /** - * JNDI name by which the data source will be registered. - * - * @since 1.1 - */ - String name(); - - /** - * Name of a DataSource class that implements javax.sql.DataSource - * or javax.sql.XADataSource or - * javax.sql.ConnectionPoolDataSource. - * - * @since 1.1 - */ - String className(); - - /** - * Description of this data source - * - * @since 1.1 - */ - String description() default ""; - - /** - * A JDBC URL. If the url annotation element contains a DataSource - * property that was also specified using the corresponding annotation element, - * the precedence order is undefined and implementation specific. - * - * @since 1.1 - */ - String url() default ""; - - /** - * User name to use for connection authentication. - * - * @since 1.1 - */ - String user() default ""; - - /** - * Password to use for connection authentication. - * - * @since 1.1 - */ - String password() default ""; - - /** - * Name of a database on a server. - * - * @since 1.1 - */ - String databaseName() default ""; - - /** - * Port number where a server is listening for requests. - * - * @since 1.1 - */ - int portNumber() default -1; - - /** - * Database server name. - * - * @since 1.1 - */ - String serverName() default "localhost"; - - /** - * Isolation level for connections. The Isolation level must be one of the - * following: - *

- *

    - *
  • Connection.TRANSACTION_NONE, - *
  • Connection.TRANSACTION_READ_ UNCOMMITTED, - *
  • Connection.TRANSACTION_READ_COMMITTED, - *
  • Connection.TRANSACTION_REPEATABLE_READ, - *
  • Connection.TRANSACTION_SERIALIZABLE - *
- *

- * Default is vendor-specific. - * - * @since 1.1 - */ - int isolationLevel() default -1; - - /** - * Set to false if connections should not participate in - * transactions. - *

- * Default is to enlist in a transaction when one is active or becomes active. - * - * @since 1.1 - */ - boolean transactional() default true; - - /** - * Number of connections that should be created when a connection pool is - * initialized. - *

- * Default is vendor-specific - * - * @since 1.1 - */ - int initialPoolSize() default -1; - - /** - * Maximum number of connections that should be concurrently allocated for a - * connection pool. - *

- * Default is vendor-specific. - * - * @since 1.1 - */ - int maxPoolSize() default -1; - - /** - * Minimum number of connections that should be allocated for a connection pool. - *

- * Default is vendor-specific. - * - * @since 1.1 - */ - int minPoolSize() default -1; - - /** - * The number of seconds that a physical connection should remain unused in the - * pool before the connection is closed for a connection pool. - *

- * Default is vendor-specific - * - * @since 1.1 - */ - int maxIdleTime() default -1; - - /** - * The total number of statements that a connection pool should keep open. A - * value of 0 indicates that the caching of statements is disabled for a - * connection pool. - *

- * Default is vendor-specific - * - * @since 1.1 - */ - int maxStatements() default -1; - - /** - * Used to specify vendor-specific properties and less commonly used - * DataSource properties such as: - *

- *

    - *
  • dataSourceName - *
  • networkProtocol - *
  • propertyCycle - *
  • roleName - *
- *

- * Properties are specified using the format: propertyName=propertyValue - * with one property per array element. - *

- * If a DataSource property is specified in the properties element - * and the annotation element for the property is also specified, the annotation - * element value takes precedence. - * - * @since 1.1 - */ - String[] properties() default {}; - - /** - * Sets the maximum time in seconds that this data source will wait while - * attempting to connect to a database. A value of zero specifies that the - * timeout is the default system timeout if there is one; otherwise, it - * specifies that there is no timeout. - *

- * Default is vendor-specific. - * - * @since 1.1 - */ - int loginTimeout() default 0; -} diff --git a/sources/main/java/javax/annotation/sql/DataSourceDefinitions.java b/sources/main/java/javax/annotation/sql/DataSourceDefinitions.java deleted file mode 100644 index d2a0ec4c..00000000 --- a/sources/main/java/javax/annotation/sql/DataSourceDefinitions.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2009-2018 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://oss.oracle.com/licenses/CDDL+GPL-1.1 - * or LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.annotation.sql; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Declares one or more DataSourceDefinition annotations. - * - * @see javax.annotation.sql.DataSourceDefinition - * @since Common Annotations 1.1 - */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface DataSourceDefinitions { - DataSourceDefinition[] value(); - -} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/ClientUUIDLoadingCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/ClientUUIDLoadingCache.java index 698c51f4..38d5bf16 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/ClientUUIDLoadingCache.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/ClientUUIDLoadingCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -22,6 +22,7 @@ import java.util.Map; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.StateFlags; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketGetOtherClientUUIDV4EAG; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.AbstractClientPlayer; @@ -53,7 +54,7 @@ public class ClientUUIDLoadingCache { if(ret == null) { Minecraft mc = Minecraft.getMinecraft(); if(mc != null && mc.thePlayer != null && mc.thePlayer.sendQueue.getEaglerMessageProtocol().ver >= 4) { - if(ignoreNonEaglerPlayers && !player.getGameProfile().getTextures().eaglerPlayer) { + if(StateFlags.eaglerPlayerFlag && player.getGameProfile().getTextures().eaglerPlayer != (byte) 2) { ret = VANILLA_UUID; }else { ret = PENDING_UUID; @@ -86,7 +87,6 @@ public class ClientUUIDLoadingCache { private static int requestId = 0; private static long lastFlushReq = EagRuntime.steadyTimeMillis(); private static long lastFlushEvict = EagRuntime.steadyTimeMillis(); - private static boolean ignoreNonEaglerPlayers = false; public static void update() { long timestamp = EagRuntime.steadyTimeMillis(); @@ -122,19 +122,21 @@ public class ClientUUIDLoadingCache { evictedUUIDs.clear(); } - private static final EaglercraftUUID MAGIC_DISABLE_NON_EAGLER_PLAYERS = new EaglercraftUUID(0xEEEEA64771094C4EL, 0x86E55B81D17E67EBL); - public static void handleResponse(int requestId, EaglercraftUUID clientId) { WaitingLookup lookup = waitingIDs.remove(requestId); if(lookup != null) { lookup.player.clientBrandUUIDCache = clientId; waitingUUIDs.remove(lookup.uuid); }else { - if(requestId == -1 && MAGIC_DISABLE_NON_EAGLER_PLAYERS.equals(clientId)) { - ignoreNonEaglerPlayers = true; - }else { - logger.warn("Unsolicited client brand UUID lookup response #{} recieved! (Brand UUID: {})", requestId, clientId); + if (requestId == -1 && StateFlags.LEGACY_EAGLER_PLAYER_FLAG_PRESENT.equals(clientId)) { + Minecraft mc = Minecraft.getMinecraft(); + if (mc != null && (mc.thePlayer == null || mc.thePlayer.sendQueue.getEaglerMessageProtocol().ver < 5)) { + StateFlags.eaglerPlayerFlag = true; + StateFlags.eaglerPlayerFlagSupervisor = true; + return; + } } + logger.warn("Unsolicited client brand UUID lookup response #{} recieved! (Brand UUID: {})", requestId, clientId); } } @@ -146,10 +148,6 @@ public class ClientUUIDLoadingCache { } } - public static void resetFlags() { - ignoreNonEaglerPlayers = false; - } - private static class WaitingLookup { private final int reqID; diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Display.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Display.java index d9778045..df8dde4a 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Display.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Display.java @@ -16,6 +16,7 @@ package net.lax1dude.eaglercraft.v1_8; +import net.lax1dude.eaglercraft.v1_8.internal.ContextLostError; import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput; public class Display { @@ -83,6 +84,12 @@ public class Display { return PlatformInput.contextLost(); } + public static void checkContextLost() { + if(PlatformInput.contextLost()) { + throw new ContextLostError(); + } + } + public static boolean wasResized() { return PlatformInput.wasResized(); } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagRuntime.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagRuntime.java index 698db4b8..8cd9d2d4 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagRuntime.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagRuntime.java @@ -69,10 +69,10 @@ public class EagRuntime { operatingSystem = PlatformRuntime.getPlatformOS(); angleBackend = PlatformRuntime.getPlatformANGLE(); UpdateService.initialize(); - EaglerXBungeeVersion.initialize(); EaglercraftGPU.warmUpCache(); ScreenRecordingController.initialize(); PlatformRuntime.postCreate(); + Display.checkContextLost(); } public static void destroy() { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerXBungeeVersion.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerXBungeeVersion.java deleted file mode 100644 index 6afaf833..00000000 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerXBungeeVersion.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2024 lax1dude. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -package net.lax1dude.eaglercraft.v1_8; - -import org.json.JSONObject; - -public class EaglerXBungeeVersion { - - public static final String pluginFileEPK = "plugin_download.zip"; - - private static String pluginName = null; - private static String pluginVersion = null; - private static long pluginVersionLong = 0l; - private static String pluginButton = null; - private static String pluginFilename = null; - - public static void initialize() { - String pluginVersionJson = EagRuntime.getRequiredResourceString("plugin_version.json"); - JSONObject json = new JSONObject(pluginVersionJson); - pluginName = json.getString("pluginName"); - pluginVersion = json.getString("pluginVersion"); - pluginVersionLong = getVersionAsLong(pluginVersion); - pluginButton = json.getString("pluginButton"); - pluginFilename = json.getString("pluginFilename"); - } - - public static String getPluginName() { - return pluginName; - } - - public static String getPluginVersion() { - return pluginVersion; - } - - public static long getPluginVersionLong() { - return pluginVersionLong; - } - - public static String getPluginButton() { - return pluginButton; - } - - public static String getPluginFilename() { - return pluginFilename; - } - - public static long getVersionAsLong(String vers) { - try { - String[] verz = vers.split("\\."); - long ret = 0; - long div = 1000000000000l; - for(int i = 0; i < verz.length; ++i) { - ret += div * Long.parseLong(verz[i]); - div /= 10000l; - } - return ret; - }catch(Throwable t) { - return -1l; - } - } - - public static byte[] getPluginDownload() { - return EagRuntime.getRequiredResourceBytes(pluginFileEPK); - } - - public static void startPluginDownload() { - EagRuntime.downloadFileWithName(pluginFilename, getPluginDownload()); - } - - public static boolean isUpdateToPluginAvailable(String brand, String vers) { - if(pluginVersionLong == -1l || !pluginName.equals(brand)) { - return false; - } - long verz = getVersionAsLong(vers); - return verz != -1l && verz < pluginVersionLong; - } -} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java index 6c64f74c..ad5964f6 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java @@ -10,7 +10,7 @@ public class EaglercraftVersion { /// Customize these to fit your fork: public static final String projectForkName = "EaglercraftX"; - public static final String projectForkVersion = "u50"; + public static final String projectForkVersion = "u51"; public static final String projectForkVendor = "lax1dude"; public static final String projectForkURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; @@ -20,20 +20,20 @@ public class EaglercraftVersion { public static final String projectOriginName = "EaglercraftX"; public static final String projectOriginAuthor = "lax1dude"; public static final String projectOriginRevision = "1.8"; - public static final String projectOriginVersion = "u50"; + public static final String projectOriginVersion = "u51"; public static final String projectOriginURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; // rest in peace // EPK Version Identifier - public static final String EPKVersionIdentifier = "u50"; // Set to null to disable EPK version check + public static final String EPKVersionIdentifier = "u51"; // Set to null to disable EPK version check // Updating configuration public static final boolean enableUpdateService = true; public static final String updateBundlePackageName = "net.lax1dude.eaglercraft.v1_8.client"; - public static final int updateBundlePackageVersionInt = 50; + public static final int updateBundlePackageVersionInt = 51; public static final String updateLatestLocalStorageKey = "latestUpdate_" + updateBundlePackageName; diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/PauseMenuCustomizeState.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/PauseMenuCustomizeState.java index 5369123f..e7246fac 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/PauseMenuCustomizeState.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/PauseMenuCustomizeState.java @@ -150,8 +150,7 @@ public class PauseMenuCustomizeState { case DISCORD_MODE_NONE: default: discordButtonText = null; - serverInfoURL = null; - serverInfoHash = null; + discordInviteURL = null; break; case DISCORD_MODE_INVITE_URL: discordButtonText = packet.discordButtonText; diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/HardwareFingerprint.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/HardwareFingerprint.java index f1718c19..3ed609c2 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/HardwareFingerprint.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/HardwareFingerprint.java @@ -43,6 +43,7 @@ import java.util.List; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.Base64; +import net.lax1dude.eaglercraft.v1_8.Display; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.crypto.GeneralDigest; @@ -108,6 +109,7 @@ public class HardwareFingerprint { _wglShaderSource(vert, GLSLHeader.getVertexHeaderCompat(vshLocalSrc, DrawUtils.vertexShaderPrecision)); _wglCompileShader(vert); if(_wglGetShaderi(vert, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); _wglDeleteShader(vert); GlStateManager.deleteTexture(helperTexture); return new byte[0]; @@ -118,6 +120,7 @@ public class HardwareFingerprint { _wglShaderSource(frag, GLSLHeader.getFragmentHeaderCompat(EagRuntime.getRequiredResourceString("/assets/eagler/glsl/hw_fingerprint.fsh"), shaderPrecision)); _wglCompileShader(frag); if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); _wglDeleteShader(vert); _wglDeleteShader(frag); GlStateManager.deleteTexture(helperTexture); @@ -142,6 +145,7 @@ public class HardwareFingerprint { _wglDeleteShader(frag); if(_wglGetProgrami(program, GL_LINK_STATUS) != GL_TRUE) { + Display.checkContextLost(); _wglDeleteProgram(program); GlStateManager.deleteTexture(helperTexture); return new byte[0]; diff --git a/sources/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TextDecoder.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/ContextLostError.java similarity index 66% rename from sources/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TextDecoder.java rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/ContextLostError.java index 3703b19b..4b50fb53 100644 --- a/sources/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TextDecoder.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/ContextLostError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -14,19 +14,12 @@ * */ -package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm; +package net.lax1dude.eaglercraft.v1_8.internal; -import org.teavm.jso.JSClass; -import org.teavm.jso.JSObject; -import org.teavm.jso.core.JSString; -import org.teavm.jso.typedarrays.Uint8Array; +public class ContextLostError extends Error { -@JSClass -public class TextDecoder implements JSObject { - - public TextDecoder(String encoding) { + public ContextLostError() { + super("WebGL context lost! Please refresh the page to continue"); } - public native JSString decode(Uint8Array buffer); - -} \ No newline at end of file +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IVertexArrayGL.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IVertexArrayGL.java index 67ba3808..45f94727 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IVertexArrayGL.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IVertexArrayGL.java @@ -18,4 +18,10 @@ package net.lax1dude.eaglercraft.v1_8.internal; public interface IVertexArrayGL extends IObjectGL { + int getBits(); + + void setBit(int bit); + + void unsetBit(int bit); + } \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/MainMenuSkyboxTexture.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/MainMenuSkyboxTexture.java index cb2c20f6..a548b9c8 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/MainMenuSkyboxTexture.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/MainMenuSkyboxTexture.java @@ -55,10 +55,10 @@ public class MainMenuSkyboxTexture extends AbstractTexture { GlStateManager.bindTexture(tex); _wglFramebufferTexture2D(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, EaglercraftGPU.getNativeTexture(tex), 0); + _wglDrawBuffers(_GL_COLOR_ATTACHMENT0); }else { _wglBindFramebuffer(_GL_FRAMEBUFFER, framebuffer); } - _wglDrawBuffers(new int[] { _GL_COLOR_ATTACHMENT0 }); } public void deleteGlTexture() { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/mojang/authlib/GameProfile.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/mojang/authlib/GameProfile.java index a46d23ff..87c9bc3b 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/mojang/authlib/GameProfile.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/mojang/authlib/GameProfile.java @@ -78,8 +78,10 @@ public class GameProfile { } public String toString() { - return (new ToStringBuilder(this)).append("id", this.id).append("name", this.name) - .append("legacy", false).toString(); + return "GameProfile{id=" + this.id + ", name=" + this.name + ", legacy=false}"; + //TODO: uncomment once JS runtime is updated to newer TeaVM version + //return (new ToStringBuilder(this)).append("id", this.id).append("name", this.name) + // .append("legacy", false).toString(); } public boolean isLegacy() { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/mojang/authlib/TexturesProperty.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/mojang/authlib/TexturesProperty.java index 4d788cde..f26fd641 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/mojang/authlib/TexturesProperty.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/mojang/authlib/TexturesProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -22,48 +22,66 @@ import org.json.JSONObject; import net.lax1dude.eaglercraft.v1_8.ArrayUtils; import net.lax1dude.eaglercraft.v1_8.Base64; +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.profile.SkinModel; +import net.lax1dude.eaglercraft.v1_8.profile.SkinPackets; public class TexturesProperty { public final String skin; - public final String model; + public final SkinModel model; public final String cape; - public final boolean eaglerPlayer; + public final byte eaglerPlayer; - public static final TexturesProperty defaultNull = new TexturesProperty(null, "default", null, false); + private EaglercraftUUID skinTextureUUID; - private TexturesProperty(String skin, String model, String cape, boolean eaglerPlayer) { + public static final TexturesProperty[] defaultNull = new TexturesProperty[] { + new TexturesProperty(null, SkinModel.STEVE, null, (byte) 0), + new TexturesProperty(null, SkinModel.STEVE, null, (byte) 1), + new TexturesProperty(null, SkinModel.STEVE, null, (byte) 2) + }; + + private TexturesProperty(String skin, SkinModel model, String cape, byte eaglerPlayer) { this.skin = skin; this.model = model; this.cape = cape; this.eaglerPlayer = eaglerPlayer; } + public EaglercraftUUID loadSkinTextureUUID() { + if(skinTextureUUID == null && skin != null) { + skinTextureUUID = SkinPackets.createEaglerURLSkinUUID(skin); + } + return skinTextureUUID; + } + public static TexturesProperty parseProfile(GameProfile profile) { + String str = null; + byte isEagler = 0; + Property prop; Collection etr = profile.getProperties().get("textures"); if(!etr.isEmpty()) { - Property prop = etr.iterator().next(); - String str; + prop = etr.iterator().next(); try { str = ArrayUtils.asciiString(Base64.decodeBase64(prop.getValue())); }catch(Throwable t) { - return defaultNull; - } - boolean isEagler = false; - etr = profile.getProperties().get("isEaglerPlayer"); - if(!etr.isEmpty()) { - prop = etr.iterator().next(); - isEagler = prop.getValue().equalsIgnoreCase("true"); } + } + etr = profile.getProperties().get("isEaglerPlayer"); + if(!etr.isEmpty()) { + prop = etr.iterator().next(); + isEagler = prop.getValue().equalsIgnoreCase("true") ? (byte) 2 : (byte) 1; + } + if(str != null) { return parseTextures(str, isEagler); }else { - return defaultNull; + return defaultNull[isEagler]; } } - public static TexturesProperty parseTextures(String string, boolean isEagler) { + public static TexturesProperty parseTextures(String string, byte isEagler) { String skin = null; - String model = "default"; + SkinModel model = SkinModel.STEVE; String cape = null; try { JSONObject json = new JSONObject(string); @@ -74,7 +92,10 @@ public class TexturesProperty { skin = skinObj.optString("url"); JSONObject meta = skinObj.optJSONObject("metadata"); if(meta != null) { - model = meta.optString("model", model); + String modelStr = meta.optString("model"); + if(modelStr != null && modelStr.equalsIgnoreCase("slim")) { + model = SkinModel.STEVE; + } } } JSONObject capeObj = json.optJSONObject("CAPE"); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationManager.java index 2a3e82eb..1ae75382 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationManager.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationManager.java @@ -39,7 +39,6 @@ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketNotifBadg import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketNotifIconsRegisterV4EAG; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketNotifIconsReleaseV4EAG; import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.PacketImageData; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.IChatComponent; @@ -56,8 +55,8 @@ public class ServerNotificationManager { private final TextureManager textureMgr; protected int unreadCounter = 0; - public ServerNotificationManager() { - this.textureMgr = Minecraft.getMinecraft().getTextureManager(); + public ServerNotificationManager(TextureManager textureMgr) { + this.textureMgr = textureMgr; } public void processPacketAddIcons(SPacketNotifIconsRegisterV4EAG packet) { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/DrawUtils.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/DrawUtils.java index 8af14831..598ac4cf 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/DrawUtils.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/DrawUtils.java @@ -21,6 +21,7 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.util.List; +import net.lax1dude.eaglercraft.v1_8.Display; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.internal.IVertexArrayGL; import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL; @@ -78,6 +79,7 @@ public class DrawUtils { _wglCompileShader(vshLocal); if(_wglGetShaderi(vshLocal, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); EaglercraftGPU.logger.error("Failed to compile GL_VERTEX_SHADER \"" + vertexShaderPath + "\"!"); String log = _wglGetShaderInfoLog(vshLocal); if(log != null) { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java index aacada58..eeedc353 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java @@ -47,6 +47,11 @@ public class EaglercraftGPU { return _wglGenBuffers(); } + @Override + protected void invalidate(IBufferGL object) { + // Don't bother + } + @Override protected void destroy(IBufferGL object) { _wglDeleteBuffers(object); @@ -61,6 +66,11 @@ public class EaglercraftGPU { return _wglGenBuffers(); } + @Override + protected void invalidate(IBufferGL object) { + // Don't bother + } + @Override protected void destroy(IBufferGL object) { _wglDeleteBuffers(object); @@ -68,13 +78,32 @@ public class EaglercraftGPU { }; - static final GLObjectRecycler VAORecycler = new GLObjectRecycler(128) { + static final GLObjectRecycler VAORecycler = new GLObjectRecycler(256) { @Override protected IVertexArrayGL create() { return _wglGenVertexArrays(); } + @Override + protected void invalidate(IVertexArrayGL object) { + int i; + int bits = object.getBits(); + if(bits != 0) { + IVertexArrayGL old = currentVertexArray; + if (old != object) { + _wglBindVertexArray(object); + } + do { + i = Integer.numberOfTrailingZeros(bits); + _wglDisableVertexAttribArray(i); + } while((bits &= ~((i << 1) - 1)) != 0); + if (old != object) { + _wglBindVertexArray(old); + } + } + } + @Override protected void destroy(IVertexArrayGL object) { _wglDeleteVertexArrays(object); @@ -186,7 +215,7 @@ public class EaglercraftGPU { dp.bindQuad32 = false; } if(dp.vertexBuffer == null) { - dp.vertexBuffer = _wglGenBuffers(); + dp.vertexBuffer = createGLArrayBuffer(); } bindVAOGLArrayBufferNow(dp.vertexBuffer); @@ -250,7 +279,7 @@ public class EaglercraftGPU { bindGLVertexArray(dp.vertexArray); if(dp.mode == GL_QUADS) { int cnt = dp.count; - if(cnt > 0xFFFF) { + if(cnt > quad16MaxVertices) { if(!dp.bindQuad32) { dp.bindQuad16 = false; dp.bindQuad32 = true; @@ -258,16 +287,14 @@ public class EaglercraftGPU { }else { attachQuad32EmulationBuffer(cnt, false); } - p.drawElements(GL_TRIANGLES, cnt + (cnt >> 1), GL_UNSIGNED_INT, 0); + p.drawElements(GL_TRIANGLES, (cnt >> 2) * 6, GL_UNSIGNED_INT, 0); }else { if(!dp.bindQuad16) { dp.bindQuad16 = true; dp.bindQuad32 = false; - attachQuad16EmulationBuffer(cnt, true); - }else { - attachQuad16EmulationBuffer(cnt, false); + attachQuad16EmulationBuffer(true); } - p.drawElements(GL_TRIANGLES, cnt + (cnt >> 1), GL_UNSIGNED_SHORT, 0); + p.drawElements(GL_TRIANGLES, (cnt >> 2) * 6, GL_UNSIGNED_SHORT, 0); } }else { p.drawArrays(dp.mode, 0, dp.count); @@ -436,7 +463,7 @@ public class EaglercraftGPU { } public static void destroyGLArrayBuffer(IBufferGL buffer) { - arrayBufferRecycler.destroy(buffer); + arrayBufferRecycler.destroyObject(buffer); } public static IBufferGL createGLElementArrayBuffer() { @@ -444,7 +471,7 @@ public class EaglercraftGPU { } public static void destroyGLElementArrayBuffer(IBufferGL buffer) { - elementArrayBufferRecycler.destroy(buffer); + elementArrayBufferRecycler.destroyObject(buffer); } public static boolean areVAOsEmulated() { @@ -461,7 +488,7 @@ public class EaglercraftGPU { public static void destroyGLVertexArray(IVertexArrayGL buffer) { if(!emulatedVAOs) { - VAORecycler.destroy(buffer); + VAORecycler.destroyObject(buffer); } } @@ -694,7 +721,7 @@ public class EaglercraftGPU { public static final int CLEAR_BINDING_TEXTURE = 1; public static final int CLEAR_BINDING_TEXTURE0 = 2; public static final int CLEAR_BINDING_ACTIVE_TEXTURE = 4; - public static final int CLEAR_BINDING_BUFFER_ARRAY = 8; + public static final int CLEAR_BINDING_VERTEX_ARRAY = 8; public static final int CLEAR_BINDING_ARRAY_BUFFER = 16; public static final int CLEAR_BINDING_SHADER_PROGRAM = 32; @@ -712,7 +739,7 @@ public class EaglercraftGPU { GlStateManager.activeTexture = 0; _wglActiveTexture(GL_TEXTURE0); } - if((mask & CLEAR_BINDING_BUFFER_ARRAY) != 0) { + if((mask & CLEAR_BINDING_VERTEX_ARRAY) != 0) { currentVertexArray = null; } if((mask & CLEAR_BINDING_ARRAY_BUFFER) != 0) { @@ -757,11 +784,11 @@ public class EaglercraftGPU { private static long lastRecyclerFlush = 0l; public static void optimize() { - FixedFunctionPipeline.optimize(); long millis = EagRuntime.steadyTimeMillis(); if(millis - lastRecyclerFlush > 120000l) { lastRecyclerFlush = millis; arrayBufferRecycler.compact(); + elementArrayBufferRecycler.compact(); VAORecycler.compact(); } } @@ -778,34 +805,21 @@ public class EaglercraftGPU { lastRender.update().drawDirectArrays(lastMode, 0, lastCount); } + public static final int quad16MaxVertices = 65536; + private static IBufferGL quad16EmulationBuffer = null; - private static int quad16EmulationBufferSize = 0; private static IBufferGL quad32EmulationBuffer = null; private static int quad32EmulationBufferSize = 0; - public static void attachQuad16EmulationBuffer(int vertexCount, boolean bind) { + public static void attachQuad16EmulationBuffer(boolean bind) { IBufferGL buf = quad16EmulationBuffer; if(buf == null) { quad16EmulationBuffer = buf = _wglGenBuffers(); - int newSize = quad16EmulationBufferSize = (vertexCount & 0xFFFFF000) + 0x2000; - if(newSize > 0xFFFF) { - newSize = 0xFFFF; - } EaglercraftGPU.bindVAOGLElementArrayBufferNow(buf); - resizeQuad16EmulationBuffer(newSize >> 2); - }else { - int cnt = quad16EmulationBufferSize; - if(cnt < vertexCount) { - int newSize = quad16EmulationBufferSize = (vertexCount & 0xFFFFF000) + 0x2000; - if(newSize > 0xFFFF) { - newSize = 0xFFFF; - } - EaglercraftGPU.bindVAOGLElementArrayBufferNow(buf); - resizeQuad16EmulationBuffer(newSize >> 2); - }else if(bind) { - EaglercraftGPU.bindVAOGLElementArrayBuffer(buf); - } + resizeQuad16EmulationBuffer(quad16MaxVertices >> 2); + }else if(bind) { + EaglercraftGPU.bindVAOGLElementArrayBuffer(buf); } } @@ -813,13 +827,13 @@ public class EaglercraftGPU { IBufferGL buf = quad32EmulationBuffer; if(buf == null) { quad32EmulationBuffer = buf = _wglGenBuffers(); - int newSize = quad32EmulationBufferSize = (vertexCount & 0xFFFFC000) + 0x8000; + int newSize = quad32EmulationBufferSize = (vertexCount + 0xFFFF) & 0xFFFF0000; EaglercraftGPU.bindVAOGLElementArrayBufferNow(buf); resizeQuad32EmulationBuffer(newSize >> 2); }else { int cnt = quad32EmulationBufferSize; if(cnt < vertexCount) { - int newSize = quad32EmulationBufferSize = (vertexCount & 0xFFFFC000) + 0x8000; + int newSize = quad32EmulationBufferSize = (vertexCount + 0xFFFF) & 0xFFFF0000; EaglercraftGPU.bindVAOGLElementArrayBufferNow(buf); resizeQuad32EmulationBuffer(newSize >> 2); }else if(bind) { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EffectPipelineFXAA.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EffectPipelineFXAA.java index a7d5285b..7d4c09ee 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EffectPipelineFXAA.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EffectPipelineFXAA.java @@ -26,6 +26,9 @@ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; + +import net.lax1dude.eaglercraft.v1_8.Display; + import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*; import net.lax1dude.eaglercraft.v1_8.EagRuntime; @@ -41,8 +44,9 @@ public class EffectPipelineFXAA { private static final int _GL_RENDERBUFFER = 0x8D41; private static final int _GL_COLOR_ATTACHMENT0 = 0x8CE0; private static final int _GL_DEPTH_ATTACHMENT = 0x8D00; - private static final int _GL_DEPTH_COMPONENT16 = 0x81A5; private static final int _GL_DEPTH_COMPONENT32F = 0x8CAC; + private static final int _GL_DEPTH_STENCIL_ATTACHMENT = 0x821A; + private static final int _GL_DEPTH_STENCIL = 0x84F9; private static IProgramGL shaderProgram = null; private static IUniformGL u_screenSize2f = null; @@ -63,6 +67,7 @@ public class EffectPipelineFXAA { _wglCompileShader(frag); if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); logger.error("Failed to compile GL_FRAGMENT_SHADER \"" + fragmentShaderPath + "\" for EffectPipelineFXAA!"); String log = _wglGetShaderInfoLog(frag); if(log != null) { @@ -91,6 +96,7 @@ public class EffectPipelineFXAA { _wglDeleteShader(frag); if(_wglGetProgrami(shaderProgram, GL_LINK_STATUS) != GL_TRUE) { + Display.checkContextLost(); logger.error("Failed to link shader program for EffectPipelineFXAA!"); String log = _wglGetProgramInfoLog(shaderProgram); if(log != null) { @@ -121,8 +127,11 @@ public class EffectPipelineFXAA { _wglBindRenderbuffer(_GL_RENDERBUFFER, framebufferDepth); _wglBindFramebuffer(_GL_FRAMEBUFFER, framebuffer); - _wglFramebufferTexture2D(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, EaglercraftGPU.getNativeTexture(framebufferColor), 0); - _wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, _GL_DEPTH_ATTACHMENT, _GL_RENDERBUFFER, framebufferDepth); + _wglFramebufferTexture2D(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + EaglercraftGPU.getNativeTexture(framebufferColor), 0); + _wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, + EaglercraftGPU.checkOpenGLESVersion() == 200 ? _GL_DEPTH_STENCIL_ATTACHMENT : _GL_DEPTH_ATTACHMENT, + _GL_RENDERBUFFER, framebufferDepth); _wglBindFramebuffer(_GL_FRAMEBUFFER, null); } @@ -136,7 +145,8 @@ public class EffectPipelineFXAA { EaglercraftGPU.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null); _wglBindRenderbuffer(_GL_RENDERBUFFER, framebufferDepth); - _wglRenderbufferStorage(_GL_RENDERBUFFER, EaglercraftGPU.checkOpenGLESVersion() == 200 ? _GL_DEPTH_COMPONENT16 : _GL_DEPTH_COMPONENT32F, width, height); + _wglRenderbufferStorage(_GL_RENDERBUFFER, EaglercraftGPU.checkOpenGLESVersion() == 200 ? _GL_DEPTH_STENCIL + : _GL_DEPTH_COMPONENT32F, width, height); } _wglBindFramebuffer(_GL_FRAMEBUFFER, framebuffer); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionPipeline.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionPipeline.java index 1f8ef4d2..2abd6c34 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionPipeline.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionPipeline.java @@ -24,7 +24,7 @@ import java.util.List; import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer; import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer; - +import net.lax1dude.eaglercraft.v1_8.Display; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.internal.IVertexArrayGL; import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL; @@ -153,7 +153,7 @@ public class FixedFunctionPipeline { EaglercraftGPU.bindGLShaderProgram(shaderProgram); if(mode == GL_QUADS) { StreamBufferInstance sb = currentVertexArray; - if(count > 0xFFFF) { + if(count > EaglercraftGPU.quad16MaxVertices) { if(!sb.bindQuad32) { sb.bindQuad16 = false; sb.bindQuad32 = true; @@ -161,18 +161,14 @@ public class FixedFunctionPipeline { }else { EaglercraftGPU.attachQuad32EmulationBuffer(count, false); } - EaglercraftGPU.drawElements(GL_TRIANGLES, count + (count >> 1), - GL_UNSIGNED_INT, 0); + EaglercraftGPU.drawElements(GL_TRIANGLES, (count >> 2) * 6, GL_UNSIGNED_INT, 0); }else { if(!sb.bindQuad16) { sb.bindQuad16 = true; sb.bindQuad32 = false; - EaglercraftGPU.attachQuad16EmulationBuffer(count, true); - }else { - EaglercraftGPU.attachQuad16EmulationBuffer(count, false); + EaglercraftGPU.attachQuad16EmulationBuffer(true); } - EaglercraftGPU.drawElements(GL_TRIANGLES, count + (count >> 1), - GL_UNSIGNED_SHORT, 0); + EaglercraftGPU.drawElements(GL_TRIANGLES, (count >> 2) * 6, GL_UNSIGNED_SHORT, 0); } }else { EaglercraftGPU.drawArrays(mode, offset, count); @@ -291,6 +287,7 @@ public class FixedFunctionPipeline { _wglCompileShader(vsh); if(_wglGetShaderi(vsh, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); LOGGER.error("Failed to compile GL_VERTEX_SHADER for state {} !", (visualizeBits(coreBits) + (enableExt && extBits != 0 ? " ext " + visualizeBits(extBits) : ""))); String log = _wglGetShaderInfoLog(vsh); if(log != null) { @@ -309,6 +306,7 @@ public class FixedFunctionPipeline { _wglCompileShader(fsh); if(_wglGetShaderi(fsh, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); LOGGER.error("Failed to compile GL_FRAGMENT_SHADER for state {} !", (visualizeBits(coreBits) + (enableExt && extBits != 0 ? " ext " + visualizeBits(extBits) : ""))); String log = _wglGetShaderInfoLog(fsh); if(log != null) { @@ -563,6 +561,7 @@ public class FixedFunctionPipeline { _wglLinkProgram(compiledProg); if(_wglGetProgrami(compiledProg, GL_LINK_STATUS) != GL_TRUE) { + Display.checkContextLost(); LOGGER.error("Program could not be linked for state {} !", (visualizeBits(bits) + (extensionProvider != null && extBits != 0 ? " ext " + visualizeBits(extBits) : ""))); String log = _wglGetProgramInfoLog(compiledProg); if(log != null) { @@ -574,8 +573,7 @@ public class FixedFunctionPipeline { throw new IllegalStateException("Program could not be linked!"); } - streamBuffer = new StreamBuffer(FixedFunctionShader.initialSize, FixedFunctionShader.initialCount, - FixedFunctionShader.maxCount, (vertexArray, vertexBuffer) -> { + streamBuffer = new StreamBuffer((vertexArray, vertexBuffer) -> { EaglercraftGPU.bindGLVertexArray(vertexArray); EaglercraftGPU.bindVAOGLArrayBuffer(vertexBuffer); @@ -1063,12 +1061,6 @@ public class FixedFunctionPipeline { return this; } - static void optimize() { - for(int i = 0, l = pipelineListTracker.size(); i < l; ++i) { - pipelineListTracker.get(i).streamBuffer.optimize(); - } - } - public static void flushCache() { shaderSourceCacheVSH = null; shaderSourceCacheFSH = null; diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionShader.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionShader.java index 21a24d7a..f6d9f342 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionShader.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionShader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved. + * Copyright (c) 2022-2023 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -18,10 +18,6 @@ package net.lax1dude.eaglercraft.v1_8.opengl; public class FixedFunctionShader { - public static final int initialSize = 0x8000; - public static final int initialCount = 3; - public static final int maxCount = 8; - public class FixedFunctionState { public static final int fixedFunctionStatesCount = 12; diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GLObjectRecycler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GLObjectRecycler.java index 2c9bcd6f..eb139099 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GLObjectRecycler.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GLObjectRecycler.java @@ -40,6 +40,7 @@ public abstract class GLObjectRecycler { } public void destroyObject(T obj) { + invalidate(obj); deletedObjects.addLast(obj); } @@ -51,6 +52,8 @@ public abstract class GLObjectRecycler { protected abstract T create(); + protected abstract void invalidate(T object); + protected abstract void destroy(T object); } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedFontRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedFontRenderer.java index 12f9b04c..5256ac09 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedFontRenderer.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedFontRenderer.java @@ -19,6 +19,7 @@ package net.lax1dude.eaglercraft.v1_8.opengl; import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*; import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; +import net.lax1dude.eaglercraft.v1_8.Display; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.internal.IVertexArrayGL; import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL; @@ -91,6 +92,7 @@ public class InstancedFontRenderer { _wglCompileShader(vert); if(_wglGetShaderi(vert, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); logger.error("Failed to compile GL_VERTEX_SHADER \"" + vertexShaderPath + "\" for InstancedFontRenderer!"); String log = _wglGetShaderInfoLog(vert); if(log != null) { @@ -106,6 +108,7 @@ public class InstancedFontRenderer { _wglCompileShader(frag); if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); logger.error("Failed to compile GL_FRAGMENT_SHADER \"" + fragmentShaderPath + "\" for InstancedFontRenderer!"); String log = _wglGetShaderInfoLog(frag); if(log != null) { @@ -135,6 +138,7 @@ public class InstancedFontRenderer { _wglDeleteShader(frag); if(_wglGetProgrami(shaderProgram, GL_LINK_STATUS) != GL_TRUE) { + Display.checkContextLost(); logger.error("Failed to link shader program for InstancedFontRenderer!"); String log = _wglGetProgramInfoLog(shaderProgram); if(log != null) { @@ -203,7 +207,7 @@ public class InstancedFontRenderer { EaglercraftGPU.vertexAttribDivisor(0, 0); EaglercraftGPU.bindVAOGLArrayBufferNow(instancesBuffer); - _wglBufferData(GL_ARRAY_BUFFER, fontDataBuffer.remaining(), GL_STREAM_DRAW); + _wglBufferData(GL_ARRAY_BUFFER, fontDataBuffer.capacity(), GL_STREAM_DRAW); EaglercraftGPU.enableVertexAttribArray(1); EaglercraftGPU.vertexAttribPointer(1, 2, GL_SHORT, false, 10, 0); @@ -377,6 +381,7 @@ public class InstancedFontRenderer { int l = fontDataBuffer.limit(); fontDataBuffer.flip(); + _wglBufferData(GL_ARRAY_BUFFER, fontDataBuffer.capacity(), GL_STREAM_DRAW); _wglBufferSubData(GL_ARRAY_BUFFER, 0, fontDataBuffer); fontDataBuffer.position(p); @@ -390,6 +395,7 @@ public class InstancedFontRenderer { int l = fontBoldDataBuffer.limit(); fontBoldDataBuffer.flip(); + _wglBufferData(GL_ARRAY_BUFFER, fontBoldDataBuffer.capacity(), GL_STREAM_DRAW); _wglBufferSubData(GL_ARRAY_BUFFER, 0, fontBoldDataBuffer); fontBoldDataBuffer.position(p); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedParticleRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedParticleRenderer.java index 5a31b188..a3f1d052 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedParticleRenderer.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedParticleRenderer.java @@ -19,6 +19,7 @@ package net.lax1dude.eaglercraft.v1_8.opengl; import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*; import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; +import net.lax1dude.eaglercraft.v1_8.Display; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.internal.IVertexArrayGL; import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL; @@ -92,6 +93,7 @@ public class InstancedParticleRenderer { _wglCompileShader(vert); if(_wglGetShaderi(vert, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); logger.error("Failed to compile GL_VERTEX_SHADER \"" + vertexShaderPath + "\" for InstancedParticleRenderer!"); String log = _wglGetShaderInfoLog(vert); if(log != null) { @@ -107,6 +109,7 @@ public class InstancedParticleRenderer { _wglCompileShader(frag); if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); logger.error("Failed to compile GL_FRAGMENT_SHADER \"" + fragmentShaderPath + "\" for InstancedParticleRenderer!"); String log = _wglGetShaderInfoLog(frag); if(log != null) { @@ -136,6 +139,7 @@ public class InstancedParticleRenderer { _wglDeleteShader(frag); if(_wglGetProgrami(shaderProgram, GL_LINK_STATUS) != GL_TRUE) { + Display.checkContextLost(); logger.error("Failed to link shader program for InstancedParticleRenderer!"); String log = _wglGetProgramInfoLog(shaderProgram); if(log != null) { @@ -184,7 +188,7 @@ public class InstancedParticleRenderer { EaglercraftGPU.vertexAttribDivisor(0, 0); EaglercraftGPU.bindVAOGLArrayBufferNow(instancesBuffer); - _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.remaining(), GL_STREAM_DRAW); + _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.capacity(), GL_STREAM_DRAW); EaglercraftGPU.enableVertexAttribArray(1); EaglercraftGPU.vertexAttribPointer(1, 3, GL_FLOAT, false, 24, 0); @@ -311,6 +315,7 @@ public class InstancedParticleRenderer { int l = particleBuffer.limit(); particleBuffer.flip(); + _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.capacity(), GL_STREAM_DRAW); _wglBufferSubData(GL_ARRAY_BUFFER, 0, particleBuffer); particleBuffer.position(p); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLVertexArray.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLVertexArray.java index 99763af0..df96856d 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLVertexArray.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLVertexArray.java @@ -223,4 +223,17 @@ class SoftGLVertexArray implements IVertexArrayGL { } + @Override + public int getBits() { + return enabled; + } + + @Override + public void setBit(int bit) { + } + + @Override + public void unsetBit(int bit) { + } + } \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SpriteLevelMixer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SpriteLevelMixer.java index f2d3fe6f..a8991b77 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SpriteLevelMixer.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SpriteLevelMixer.java @@ -22,6 +22,7 @@ import java.util.List; import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*; +import net.lax1dude.eaglercraft.v1_8.Display; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL; import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL; @@ -78,6 +79,7 @@ public class SpriteLevelMixer { _wglCompileShader(frag); if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); LOGGER.error("Failed to compile GL_FRAGMENT_SHADER \"" + fragmentShaderPath + "\" for SpriteLevelMixer!"); String log = _wglGetShaderInfoLog(frag); if(log != null) { @@ -106,6 +108,7 @@ public class SpriteLevelMixer { _wglDeleteShader(frag); if(_wglGetProgrami(shaderProgram, GL_LINK_STATUS) != GL_TRUE) { + Display.checkContextLost(); LOGGER.error("Failed to link shader program for SpriteLevelMixer!"); String log = _wglGetProgramInfoLog(shaderProgram); if(log != null) { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/StreamBuffer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/StreamBuffer.java index 445551cc..8179ff71 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/StreamBuffer.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/StreamBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024 lax1dude. All Rights Reserved. + * Copyright (c) 2023-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -24,11 +24,7 @@ import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*; public class StreamBuffer { - public static final int poolSize = 16; - - public final int initialSize; - public final int initialCount; - public final int maxCount; + public static final int poolSize = 4; protected static final PoolInstance[] pool = new PoolInstance[poolSize]; protected static int poolBufferID = 0; @@ -55,21 +51,23 @@ public class StreamBuffer { } private static void resizeInstance(PoolInstance instance, int requiredMemory) { - if(instance.vertexBuffer == null) { - instance.vertexBuffer = _wglGenBuffers(); + IBufferGL buffer = instance.vertexBuffer; + if (buffer == null) { + buffer = _wglGenBuffers(); + instance.vertexBuffer = buffer; } - if(instance.vertexBufferSize < requiredMemory) { - int newSize = (requiredMemory & 0xFFFFF000) + 0x2000; - EaglercraftGPU.bindGLArrayBuffer(instance.vertexBuffer); - _wglBufferData(GL_ARRAY_BUFFER, newSize, GL_STREAM_DRAW); + int newSize = instance.vertexBufferSize; + if (newSize < requiredMemory) { + newSize = (requiredMemory + 0xFFFF) & 0xFFFF0000; instance.vertexBufferSize = newSize; } + EaglercraftGPU.bindGLArrayBuffer(buffer); + _wglBufferData(GL_ARRAY_BUFFER, newSize, GL_STREAM_DRAW); } protected StreamBufferInstance[] buffers; protected int currentBufferId = 0; - protected int overflowCounter = 0; protected final IStreamBufferInitializer initializer; @@ -95,19 +93,20 @@ public class StreamBuffer { void initialize(IVertexArrayGL vertexArray, IBufferGL vertexBuffer); } - public StreamBuffer(int initialSize, int initialCount, int maxCount, IStreamBufferInitializer initializer) { - if(maxCount > poolSize) { - maxCount = poolSize; + public StreamBuffer(IStreamBufferInitializer initializer) { + this(poolSize, initializer); + } + + public StreamBuffer(int count, IStreamBufferInitializer initializer) { + if(count > poolSize) { + count = poolSize; } - this.buffers = new StreamBufferInstance[initialCount]; + this.buffers = new StreamBufferInstance[count]; for(int i = 0; i < this.buffers.length; ++i) { StreamBufferInstance j = new StreamBufferInstance(); j.poolInstance = fillPoolInstance(); this.buffers[i] = j; } - this.initialSize = initialSize; - this.initialCount = initialCount; - this.maxCount = maxCount; this.initializer = initializer; } @@ -121,67 +120,6 @@ public class StreamBuffer { return next; } - public void optimize() { - overflowCounter += currentBufferId - buffers.length; - if(overflowCounter < -25) { - int newCount = buffers.length - 1 + ((overflowCounter + 25) / 5); - if(newCount < initialCount) { - newCount = initialCount; - } - if(newCount < buffers.length) { - StreamBufferInstance[] newArray = new StreamBufferInstance[newCount]; - for(int i = 0; i < buffers.length; ++i) { - if(i < newArray.length) { - newArray[i] = buffers[i]; - }else { - if(buffers[i].vertexArray != null) { - EaglercraftGPU.destroyGLVertexArray(buffers[i].vertexArray); - } - } - } - buffers = newArray; - refill(); - } - overflowCounter = 0; - }else if(overflowCounter > 15) { - int newCount = buffers.length + 1 + ((overflowCounter - 15) / 5); - if(newCount > maxCount) { - newCount = maxCount; - } - if(newCount > buffers.length) { - StreamBufferInstance[] newArray = new StreamBufferInstance[newCount]; - for(int i = 0; i < newArray.length; ++i) { - if(i < buffers.length) { - newArray[i] = buffers[i]; - }else { - newArray[i] = new StreamBufferInstance(); - } - } - buffers = newArray; - refill(); - } - overflowCounter = 0; - } - currentBufferId = 0; - } - - private void refill() { - for(int i = 0; i < buffers.length; ++i) { - PoolInstance j = fillPoolInstance(); - StreamBufferInstance k = buffers[i]; - if(j != k.poolInstance) { - PoolInstance l = k.poolInstance; - k.poolInstance = j; - if(k.vertexArray != null) { - if(j.vertexBuffer == null) { - resizeInstance(j, l.vertexBufferSize); - } - initializer.initialize(k.vertexArray, j.vertexBuffer); - } - } - } - } - public void destroy() { for(int i = 0; i < buffers.length; ++i) { StreamBufferInstance next = buffers[i]; @@ -189,12 +127,6 @@ public class StreamBuffer { EaglercraftGPU.destroyGLVertexArray(next.vertexArray); } } - buffers = new StreamBufferInstance[initialCount]; - for(int i = 0; i < initialCount; ++i) { - StreamBufferInstance j = new StreamBufferInstance(); - j.poolInstance = fillPoolInstance(); - buffers[i] = j; - } } public static void destroyPool() { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureCopyUtil.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureCopyUtil.java index 2e2cb5ff..89fa565f 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureCopyUtil.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureCopyUtil.java @@ -21,6 +21,7 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.util.List; +import net.lax1dude.eaglercraft.v1_8.Display; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL; import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL; @@ -100,6 +101,7 @@ public class TextureCopyUtil { _wglCompileShader(vshShader); if(_wglGetShaderi(vshShader, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); LOGGER.error("Failed to compile GL_VERTEX_SHADER \"" + vertexShaderPath + "\" for TextureCopyUtil!"); String log = _wglGetShaderInfoLog(vshShader); if(log != null) { @@ -126,6 +128,7 @@ public class TextureCopyUtil { _wglCompileShader(frag); if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); LOGGER.error("Failed to compile GL_FRAGMENT_SHADER \"" + fragmentShaderPath + "\" for TextureCopyUtil!"); String log = _wglGetShaderInfoLog(frag); if(log != null) { @@ -154,6 +157,7 @@ public class TextureCopyUtil { _wglDeleteShader(frag); if(_wglGetProgrami(shaderProgram, GL_LINK_STATUS) != GL_TRUE) { + Display.checkContextLost(); LOGGER.error("Failed to link shader program for TextureCopyUtil!"); String log = _wglGetProgramInfoLog(shaderProgram); if(log != null) { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java index bfe8d518..4ea021d7 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java @@ -1483,6 +1483,7 @@ public class EaglerDeferredPipeline { GlStateManager.globalEnableBlend(); GlStateManager.enableBlend(); GlStateManager.depthMask(false); + GlStateManager.cullFace(GL_FRONT); GlStateManager.tryBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ZERO); GlStateManager.enablePolygonOffset(); GlStateManager.doPolygonOffset(0.25f, 1.0f); @@ -1497,6 +1498,7 @@ public class EaglerDeferredPipeline { GlStateManager.disableBlend(); GlStateManager.globalDisableBlend(); GlStateManager.depthMask(true); + GlStateManager.cullFace(GL_BACK); GlStateManager.disablePolygonOffset(); GlStateManager.colorMask(false, false, false, false); DeferredStateManager.checkGLError("Post: endDrawColoredShadows()"); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ForwardAcceleratedEffectRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ForwardAcceleratedEffectRenderer.java index 1bccdbac..5b907a93 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ForwardAcceleratedEffectRenderer.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ForwardAcceleratedEffectRenderer.java @@ -92,7 +92,7 @@ public class ForwardAcceleratedEffectRenderer extends AbstractAcceleratedEffectR _wglVertexAttribDivisor(0, 0); EaglercraftGPU.bindGLArrayBuffer(instancesBuffer); - _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.remaining(), GL_STREAM_DRAW); + _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.capacity(), GL_STREAM_DRAW); _wglEnableVertexAttribArray(1); _wglVertexAttribPointer(1, 3, GL_FLOAT, false, 24, 0); @@ -149,6 +149,7 @@ public class ForwardAcceleratedEffectRenderer extends AbstractAcceleratedEffectR int l = particleBuffer.limit(); particleBuffer.flip(); + _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.capacity(), GL_STREAM_DRAW); _wglBufferSubData(GL_ARRAY_BUFFER, 0, particleBuffer); particleBuffer.position(p); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/GBufferAcceleratedEffectRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/GBufferAcceleratedEffectRenderer.java index 2acad67e..378ab38d 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/GBufferAcceleratedEffectRenderer.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/GBufferAcceleratedEffectRenderer.java @@ -92,7 +92,7 @@ public class GBufferAcceleratedEffectRenderer extends AbstractAcceleratedEffectR _wglVertexAttribDivisor(0, 0); EaglercraftGPU.bindGLArrayBuffer(instancesBuffer); - _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.remaining(), GL_STREAM_DRAW); + _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.capacity(), GL_STREAM_DRAW); _wglEnableVertexAttribArray(1); _wglVertexAttribPointer(1, 3, GL_FLOAT, false, 24, 0); @@ -148,6 +148,7 @@ public class GBufferAcceleratedEffectRenderer extends AbstractAcceleratedEffectR int l = particleBuffer.limit(); particleBuffer.flip(); + _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.capacity(), GL_STREAM_DRAW); _wglBufferSubData(GL_ARRAY_BUFFER, 0, particleBuffer); particleBuffer.position(p); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/LensFlareMeshRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/LensFlareMeshRenderer.java index 30e09e32..1681934d 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/LensFlareMeshRenderer.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/LensFlareMeshRenderer.java @@ -89,7 +89,7 @@ public class LensFlareMeshRenderer { streaksVertexArray = _wglGenVertexArrays(); EaglercraftGPU.bindGLVertexArray(streaksVertexArray); - EaglercraftGPU.attachQuad16EmulationBuffer(16, true); + EaglercraftGPU.attachQuad16EmulationBuffer(true); _wglEnableVertexAttribArray(0); _wglVertexAttribPointer(0, 2, GL_FLOAT, false, 16, 0); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderCompiler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderCompiler.java index bef73d5f..3c640864 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderCompiler.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderCompiler.java @@ -22,6 +22,7 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.util.Arrays; import java.util.List; +import net.lax1dude.eaglercraft.v1_8.Display; import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL; import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; @@ -69,6 +70,7 @@ public class ShaderCompiler { _wglCompileShader(ret); if(_wglGetShaderi(ret, GL_COMPILE_STATUS) != GL_TRUE) { + Display.checkContextLost(); logger.error("Failed to compile {} \"{}\" of program \"{}\"!", getStageName(stage), filename, name); String log = _wglGetShaderInfoLog(ret); if(log != null) { @@ -95,6 +97,7 @@ public class ShaderCompiler { _wglDetachShader(ret, frag); if(_wglGetProgrami(ret, GL_LINK_STATUS) != GL_TRUE) { + Display.checkContextLost(); logger.error("Failed to link program \"{}\"!", name); String log = _wglGetProgramInfoLog(ret); if(log != null) { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightsAcceleratedEffectRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightsAcceleratedEffectRenderer.java index f837bc26..9d6c6452 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightsAcceleratedEffectRenderer.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightsAcceleratedEffectRenderer.java @@ -97,7 +97,7 @@ public class DynamicLightsAcceleratedEffectRenderer extends AbstractAcceleratedE _wglVertexAttribDivisor(0, 0); EaglercraftGPU.bindGLArrayBuffer(instancesBuffer); - _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.remaining(), GL_STREAM_DRAW); + _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.capacity(), GL_STREAM_DRAW); _wglEnableVertexAttribArray(1); _wglVertexAttribPointer(1, 3, GL_FLOAT, false, 24, 0); @@ -155,6 +155,7 @@ public class DynamicLightsAcceleratedEffectRenderer extends AbstractAcceleratedE int l = particleBuffer.limit(); particleBuffer.flip(); + _wglBufferData(GL_ARRAY_BUFFER, particleBuffer.capacity(), GL_STREAM_DRAW); _wglBufferSubData(GL_ARRAY_BUFFER, 0, particleBuffer); particleBuffer.position(p); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerProfile.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerProfile.java index 39df1354..4bdda162 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerProfile.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerProfile.java @@ -210,7 +210,6 @@ public class EaglerProfile { public static void handleForceSkinPreset(int preset) { isServerSkinOverride = true; overridePresetSkinId = preset; - ServerSkinCache.needReloadClientSkin = true; } public static void handleForceSkinCustom(int modelID, byte[] datav3) { @@ -229,13 +228,11 @@ public class EaglerProfile { }else { overrideCustomSkin.copyPixelsIn(datav3); } - ServerSkinCache.needReloadClientSkin = true; } public static void handleForceCapePreset(int preset) { isServerCapeOverride = true; overridePresetCapeId = preset; - ServerCapeCache.needReloadClientCape = true; } public static void handleForceCapeCustom(byte[] custom) { @@ -252,7 +249,6 @@ public class EaglerProfile { }else { overrideCustomCape.copyPixelsIn(pixels32x32); } - ServerCapeCache.needReloadClientCape = true; } public static void clearServerSkinOverride() { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiAuthenticationScreen.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiAuthenticationScreen.java index ad2cfa81..f028c4d4 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiAuthenticationScreen.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiAuthenticationScreen.java @@ -19,7 +19,7 @@ package net.lax1dude.eaglercraft.v1_8.profile; import net.lax1dude.eaglercraft.v1_8.Keyboard; import net.lax1dude.eaglercraft.v1_8.internal.KeyboardConstants; import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent; -import net.lax1dude.eaglercraft.v1_8.socket.ConnectionHandshake; +import net.lax1dude.eaglercraft.v1_8.socket.GuiHandshakeApprove; import net.lax1dude.eaglercraft.v1_8.socket.HandshakePacketTypes; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; @@ -64,7 +64,7 @@ public class GuiAuthenticationScreen extends GuiScreen { public void initGui() { if(authTypeForWarning != Integer.MAX_VALUE) { - GuiScreen scr = ConnectionHandshake.displayAuthProtocolConfirm(authTypeForWarning, parent, this); + GuiScreen scr = GuiHandshakeApprove.displayAuthProtocolConfirm(authTypeForWarning, parent, this); authTypeForWarning = Integer.MAX_VALUE; if(scr != null) { mc.displayGuiScreen(scr); @@ -90,7 +90,7 @@ public class GuiAuthenticationScreen extends GuiScreen { protected void actionPerformed(GuiButton parGuiButton) { if(parGuiButton.id == 1) { - this.mc.displayGuiScreen(new GuiConnecting(retAfterAuthScreen, password.getText())); + this.mc.displayGuiScreen(new GuiConnecting(retAfterAuthScreen, password.getText(), allowPlaintext)); }else { this.mc.displayGuiScreen(parent); } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerCapeCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerCapeCache.java deleted file mode 100644 index 560a2bd4..00000000 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerCapeCache.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -package net.lax1dude.eaglercraft.v1_8.profile; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import net.lax1dude.eaglercraft.v1_8.EagRuntime; -import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; -import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; -import net.lax1dude.eaglercraft.v1_8.log4j.Logger; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketGetOtherCapeEAG; -import net.minecraft.client.network.NetHandlerPlayClient; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.util.ResourceLocation; - -public class ServerCapeCache { - - private static final Logger logger = LogManager.getLogger("ServerCapeCache"); - - public class CapeCacheEntry { - - protected final boolean isPresetCape; - protected final int presetCapeId; - protected final CacheCustomCape customCape; - - protected long lastCacheHit = EagRuntime.steadyTimeMillis(); - - protected CapeCacheEntry(EaglerSkinTexture textureInstance, ResourceLocation resourceLocation) { - this.isPresetCape = false; - this.presetCapeId = -1; - this.customCape = new CacheCustomCape(textureInstance, resourceLocation); - ServerCapeCache.this.textureManager.loadTexture(resourceLocation, textureInstance); - } - - /** - * Use only for the constant for the client player - */ - protected CapeCacheEntry(ResourceLocation resourceLocation) { - this.isPresetCape = false; - this.presetCapeId = -1; - this.customCape = new CacheCustomCape(null, resourceLocation); - } - - protected CapeCacheEntry(int presetSkinId) { - this.isPresetCape = true; - this.presetCapeId = presetSkinId; - this.customCape = null; - } - - public ResourceLocation getResourceLocation() { - if(isPresetCape) { - return DefaultCapes.getCapeFromId(presetCapeId).location; - }else { - if(customCape != null) { - return customCape.resourceLocation; - }else { - return null; - } - } - } - - protected void free() { - if(!isPresetCape && customCape.resourceLocation != null) { - ServerCapeCache.this.textureManager.deleteTexture(customCape.resourceLocation); - } - } - - } - - protected static class CacheCustomCape { - - protected final EaglerSkinTexture textureInstance; - protected final ResourceLocation resourceLocation; - - protected CacheCustomCape(EaglerSkinTexture textureInstance, ResourceLocation resourceLocation) { - this.textureInstance = textureInstance; - this.resourceLocation = resourceLocation; - } - - } - - private final CapeCacheEntry defaultCacheEntry = new CapeCacheEntry(0); - private final Map capesCache = new HashMap<>(); - private final Map waitingCapes = new HashMap<>(); - private final Map evictedCapes = new HashMap<>(); - - private final NetHandlerPlayClient netHandler; - protected final TextureManager textureManager; - - private final EaglercraftUUID clientPlayerId; - private CapeCacheEntry clientPlayerCacheEntry; - - private long lastFlush = EagRuntime.steadyTimeMillis(); - private long lastFlushReq = EagRuntime.steadyTimeMillis(); - private long lastFlushEvict = EagRuntime.steadyTimeMillis(); - - private static int texId = 0; - public static boolean needReloadClientCape = false; - - public ServerCapeCache(NetHandlerPlayClient netHandler, TextureManager textureManager) { - this.netHandler = netHandler; - this.textureManager = textureManager; - this.clientPlayerId = EaglerProfile.getPlayerUUID(); - reloadClientPlayerCape(); - } - - public void reloadClientPlayerCape() { - needReloadClientCape = false; - this.clientPlayerCacheEntry = new CapeCacheEntry(EaglerProfile.getActiveCapeResourceLocation()); - } - - public CapeCacheEntry getClientPlayerCape() { - return clientPlayerCacheEntry; - } - - public CapeCacheEntry getCape(EaglercraftUUID player) { - if(player.equals(clientPlayerId)) { - return clientPlayerCacheEntry; - } - CapeCacheEntry etr = capesCache.get(player); - if(etr == null) { - if(!waitingCapes.containsKey(player) && !evictedCapes.containsKey(player)) { - waitingCapes.put(player, EagRuntime.steadyTimeMillis()); - netHandler.sendEaglerMessage(new CPacketGetOtherCapeEAG(player.msb, player.lsb)); - } - return defaultCacheEntry; - }else { - etr.lastCacheHit = EagRuntime.steadyTimeMillis(); - return etr; - } - } - - public void cacheCapePreset(EaglercraftUUID player, int presetId) { - if(waitingCapes.remove(player) != null) { - CapeCacheEntry etr = capesCache.remove(player); - if(etr != null) { - etr.free(); - } - capesCache.put(player, new CapeCacheEntry(presetId)); - }else { - logger.error("Unsolicited cape response recieved for \"{}\"! (preset {})", player, presetId); - } - } - - public void cacheCapeCustom(EaglercraftUUID player, byte[] pixels) { - if(waitingCapes.remove(player) != null) { - CapeCacheEntry etr = capesCache.remove(player); - if(etr != null) { - etr.free(); - } - byte[] pixels32x32 = new byte[4096]; - SkinConverter.convertCape23x17RGBto32x32RGBA(pixels, pixels32x32); - try { - etr = new CapeCacheEntry(new EaglerSkinTexture(pixels32x32, 32, 32), - new ResourceLocation("eagler:capes/multiplayer/tex_" + texId++)); - }catch(Throwable t) { - etr = new CapeCacheEntry(0); - logger.error("Could not process custom skin packet for \"{}\"!", player); - logger.error(t); - } - capesCache.put(player, etr); - }else { - logger.error("Unsolicited skin response recieved for \"{}\"!", player); - } - } - - public void flush() { - long millis = EagRuntime.steadyTimeMillis(); - if(millis - lastFlushReq > 5000l) { - lastFlushReq = millis; - if(!waitingCapes.isEmpty()) { - Iterator waitingItr = waitingCapes.values().iterator(); - while(waitingItr.hasNext()) { - if(millis - waitingItr.next().longValue() > 30000l) { - waitingItr.remove(); - } - } - } - } - if(millis - lastFlushEvict > 1000l) { - lastFlushEvict = millis; - if(!evictedCapes.isEmpty()) { - Iterator evictItr = evictedCapes.values().iterator(); - while(evictItr.hasNext()) { - if(millis - evictItr.next().longValue() > 3000l) { - evictItr.remove(); - } - } - } - } - if(millis - lastFlush > 60000l) { - lastFlush = millis; - if(!capesCache.isEmpty()) { - Iterator entryItr = capesCache.values().iterator(); - while(entryItr.hasNext()) { - CapeCacheEntry etr = entryItr.next(); - if(millis - etr.lastCacheHit > 900000l) { // 15 minutes - entryItr.remove(); - etr.free(); - } - } - } - } - if(needReloadClientCape) { - reloadClientPlayerCape(); - } - } - - public void destroy() { - Iterator entryItr = capesCache.values().iterator(); - while(entryItr.hasNext()) { - entryItr.next().free(); - } - capesCache.clear(); - waitingCapes.clear(); - evictedCapes.clear(); - } - - public void evictCape(EaglercraftUUID uuid) { - evictedCapes.put(uuid, Long.valueOf(EagRuntime.steadyTimeMillis())); - CapeCacheEntry etr = capesCache.remove(uuid); - if(etr != null) { - etr.free(); - } - } - - public void handleInvalidate(EaglercraftUUID uuid) { - CapeCacheEntry etr = capesCache.remove(uuid); - if(etr != null) { - etr.free(); - } - } - -} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java deleted file mode 100644 index de771d31..00000000 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -package net.lax1dude.eaglercraft.v1_8.profile; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import net.lax1dude.eaglercraft.v1_8.EagRuntime; -import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; -import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; -import net.lax1dude.eaglercraft.v1_8.log4j.Logger; -import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile; -import net.lax1dude.eaglercraft.v1_8.mojang.authlib.TexturesProperty; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketGetOtherSkinEAG; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketGetSkinByURLEAG; -import net.minecraft.client.network.NetHandlerPlayClient; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.util.ResourceLocation; - -public class ServerSkinCache { - - private static final Logger logger = LogManager.getLogger("ServerSkinCache"); - - public class SkinCacheEntry { - - protected final boolean isPresetSkin; - protected final int presetSkinId; - protected final CacheCustomSkin customSkin; - - protected long lastCacheHit = EagRuntime.steadyTimeMillis(); - - protected SkinCacheEntry(EaglerSkinTexture textureInstance, ResourceLocation resourceLocation, SkinModel model) { - this.isPresetSkin = false; - this.presetSkinId = -1; - this.customSkin = new CacheCustomSkin(textureInstance, resourceLocation, model); - ServerSkinCache.this.textureManager.loadTexture(resourceLocation, textureInstance); - } - - /** - * Use only for the constant for the client player - */ - protected SkinCacheEntry(ResourceLocation resourceLocation, SkinModel model) { - this.isPresetSkin = false; - this.presetSkinId = -1; - this.customSkin = new CacheCustomSkin(null, resourceLocation, model); - } - - protected SkinCacheEntry(int presetSkinId) { - this.isPresetSkin = true; - this.presetSkinId = presetSkinId; - this.customSkin = null; - } - - public ResourceLocation getResourceLocation() { - if(isPresetSkin) { - return DefaultSkins.getSkinFromId(presetSkinId).location; - }else { - if(customSkin != null) { - return customSkin.resourceLocation; - }else { - return DefaultSkins.DEFAULT_STEVE.location; - } - } - } - - public SkinModel getSkinModel() { - if(isPresetSkin) { - return DefaultSkins.getSkinFromId(presetSkinId).model; - }else { - if(customSkin != null) { - return customSkin.model; - }else { - return DefaultSkins.DEFAULT_STEVE.model; - } - } - } - - protected void free() { - if(!isPresetSkin) { - ServerSkinCache.this.textureManager.deleteTexture(customSkin.resourceLocation); - } - } - - } - - protected static class CacheCustomSkin { - - protected final EaglerSkinTexture textureInstance; - protected final ResourceLocation resourceLocation; - protected final SkinModel model; - - protected CacheCustomSkin(EaglerSkinTexture textureInstance, ResourceLocation resourceLocation, SkinModel model) { - this.textureInstance = textureInstance; - this.resourceLocation = resourceLocation; - this.model = model; - } - - } - - protected static class WaitingSkin { - - protected final long timeout; - protected final SkinModel model; - - protected WaitingSkin(long timeout, SkinModel model) { - this.timeout = timeout; - this.model = model; - } - - } - - private final SkinCacheEntry defaultCacheEntry = new SkinCacheEntry(0); - private final SkinCacheEntry defaultSlimCacheEntry = new SkinCacheEntry(1); - private final Map skinsCache = new HashMap<>(); - private final Map waitingSkins = new HashMap<>(); - private final Map evictedSkins = new HashMap<>(); - - private final NetHandlerPlayClient netHandler; - protected final TextureManager textureManager; - - private final EaglercraftUUID clientPlayerId; - private SkinCacheEntry clientPlayerCacheEntry; - - private long lastFlush = EagRuntime.steadyTimeMillis(); - private long lastFlushReq = EagRuntime.steadyTimeMillis(); - private long lastFlushEvict = EagRuntime.steadyTimeMillis(); - - private static int texId = 0; - public static boolean needReloadClientSkin = false; - - public ServerSkinCache(NetHandlerPlayClient netHandler, TextureManager textureManager) { - this.netHandler = netHandler; - this.textureManager = textureManager; - this.clientPlayerId = EaglerProfile.getPlayerUUID(); - reloadClientPlayerSkin(); - } - - public void reloadClientPlayerSkin() { - needReloadClientSkin = false; - this.clientPlayerCacheEntry = new SkinCacheEntry(EaglerProfile.getActiveSkinResourceLocation(), EaglerProfile.getActiveSkinModel()); - } - - public SkinCacheEntry getClientPlayerSkin() { - return clientPlayerCacheEntry; - } - - public SkinCacheEntry getSkin(GameProfile player) { - EaglercraftUUID uuid = player.getId(); - if(uuid != null && uuid.equals(clientPlayerId)) { - return clientPlayerCacheEntry; - } - TexturesProperty props = player.getTextures(); - if(props.eaglerPlayer || props.skin == null) { - if(uuid != null) { - return _getSkin(uuid); - }else { - if("slim".equalsIgnoreCase(props.model)) { - return defaultSlimCacheEntry; - }else { - return defaultCacheEntry; - } - } - }else { - return getSkin(props.skin, SkinModel.getModelFromId(props.model)); - } - } - - public SkinCacheEntry getSkin(EaglercraftUUID player) { - if(player.equals(clientPlayerId)) { - return clientPlayerCacheEntry; - } - return _getSkin(player); - } - - private SkinCacheEntry _getSkin(EaglercraftUUID player) { - SkinCacheEntry etr = skinsCache.get(player); - if(etr == null) { - if(!waitingSkins.containsKey(player) && !evictedSkins.containsKey(player)) { - waitingSkins.put(player, new WaitingSkin(EagRuntime.steadyTimeMillis(), null)); - netHandler.sendEaglerMessage(new CPacketGetOtherSkinEAG(player.msb, player.lsb)); - } - return defaultCacheEntry; - }else { - etr.lastCacheHit = EagRuntime.steadyTimeMillis(); - return etr; - } - } - - public SkinCacheEntry getSkin(String url, SkinModel skinModelResponse) { - if(url.length() > 0x7F00) { - return skinModelResponse == SkinModel.ALEX ? defaultSlimCacheEntry : defaultCacheEntry; - } - EaglercraftUUID generatedUUID = SkinPackets.createEaglerURLSkinUUID(url); - SkinCacheEntry etr = skinsCache.get(generatedUUID); - if(etr != null) { - etr.lastCacheHit = EagRuntime.steadyTimeMillis(); - return etr; - }else { - if(!waitingSkins.containsKey(generatedUUID) && !evictedSkins.containsKey(generatedUUID)) { - waitingSkins.put(generatedUUID, new WaitingSkin(EagRuntime.steadyTimeMillis(), skinModelResponse)); - netHandler.sendEaglerMessage(new CPacketGetSkinByURLEAG(generatedUUID.msb, generatedUUID.lsb, url)); - } - } - return skinModelResponse == SkinModel.ALEX ? defaultSlimCacheEntry : defaultCacheEntry; - } - - public void cacheSkinPreset(EaglercraftUUID player, int presetId) { - if(waitingSkins.remove(player) != null) { - SkinCacheEntry etr = skinsCache.remove(player); - if(etr != null) { - etr.free(); - } - skinsCache.put(player, new SkinCacheEntry(presetId)); - }else { - logger.error("Unsolicited skin response recieved for \"{}\"! (preset {})", player, presetId); - } - } - - public void cacheSkinCustom(EaglercraftUUID player, byte[] pixels, SkinModel model) { - WaitingSkin waitingSkin; - if((waitingSkin = waitingSkins.remove(player)) != null) { - SkinCacheEntry etr = skinsCache.remove(player); - if(etr != null) { - etr.free(); - } - if(waitingSkin.model != null) { - model = waitingSkin.model; - }else if(model == null) { - model = (player.hashCode() & 1) != 0 ? SkinModel.ALEX : SkinModel.STEVE; - } - try { - etr = new SkinCacheEntry(new EaglerSkinTexture(pixels, model.width, model.height), - new ResourceLocation("eagler:skins/multiplayer/tex_" + texId++), model); - }catch(Throwable t) { - etr = new SkinCacheEntry(0); - logger.error("Could not process custom skin packet for \"{}\"!", player); - logger.error(t); - } - skinsCache.put(player, etr); - }else { - logger.error("Unsolicited skin response recieved for \"{}\"! (custom {}x{})", player, model.width, model.height); - } - } - - public SkinModel getRequestedSkinType(EaglercraftUUID waiting) { - WaitingSkin waitingSkin; - if((waitingSkin = waitingSkins.get(waiting)) != null) { - return waitingSkin.model; - }else { - return null; - } - } - - public void flush() { - long millis = EagRuntime.steadyTimeMillis(); - if(millis - lastFlushReq > 5000l) { - lastFlushReq = millis; - if(!waitingSkins.isEmpty()) { - Iterator waitingItr = waitingSkins.values().iterator(); - while(waitingItr.hasNext()) { - if(millis - waitingItr.next().timeout > 20000l) { - waitingItr.remove(); - } - } - } - } - if(millis - lastFlushEvict > 1000l) { - lastFlushEvict = millis; - if(!evictedSkins.isEmpty()) { - Iterator evictItr = evictedSkins.values().iterator(); - while(evictItr.hasNext()) { - if(millis - evictItr.next().longValue() > 3000l) { - evictItr.remove(); - } - } - } - } - if(millis - lastFlush > 60000l) { - lastFlush = millis; - if(!skinsCache.isEmpty()) { - Iterator entryItr = skinsCache.values().iterator(); - while(entryItr.hasNext()) { - SkinCacheEntry etr = entryItr.next(); - if(millis - etr.lastCacheHit > 900000l) { // 15 minutes - entryItr.remove(); - etr.free(); - } - } - } - } - if(needReloadClientSkin) { - reloadClientPlayerSkin(); - } - } - - public void destroy() { - Iterator entryItr = skinsCache.values().iterator(); - while(entryItr.hasNext()) { - entryItr.next().free(); - } - skinsCache.clear(); - waitingSkins.clear(); - evictedSkins.clear(); - } - - public void evictSkin(EaglercraftUUID uuid) { - evictedSkins.put(uuid, Long.valueOf(EagRuntime.steadyTimeMillis())); - SkinCacheEntry etr = skinsCache.remove(uuid); - if(etr != null) { - etr.free(); - } - } - - public void handleInvalidate(EaglercraftUUID uuid) { - SkinCacheEntry etr = skinsCache.remove(uuid); - if(etr != null) { - etr.free(); - } - } - -} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinModel.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinModel.java index 80a60fc0..314aa9ae 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinModel.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinModel.java @@ -72,6 +72,14 @@ public enum SkinModel { return STEVE; } } + + public static SkinModel getSanitizedModelFromId(int id) { + SkinModel ret = getModelFromId(id & 0x7F); + if((id & 0x80) != 0 && ret.sanitize) { + ret = STEVE; + } + return ret; + } static { SkinModel[] arr = values(); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ForeignTextureEntry.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ForeignTextureEntry.java new file mode 100644 index 00000000..6fc812dc --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ForeignTextureEntry.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.skin_cache; + +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.profile.DefaultSkins; +import net.lax1dude.eaglercraft.v1_8.profile.EaglerSkinTexture; +import net.lax1dude.eaglercraft.v1_8.profile.SkinModel; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.util.ResourceLocation; + +class ForeignTextureEntry extends SkinData { + + protected final EaglercraftUUID uuid; + protected final String url; + + protected int state; + + protected long lastHit; + + protected ResourceLocation skinLocation; + protected EaglerSkinTexture skinTexture; + protected SkinModel skinModel; + + protected SkinData inverseModel; + + public ForeignTextureEntry(EaglercraftUUID uuid, String url, SkinModel skinModel) { + this.uuid = uuid; + this.url = url; + this.skinModel = skinModel; + } + + @Override + public ResourceLocation getLocation() { + return skinLocation; + } + + @Override + public SkinModel getModel() { + return skinModel; + } + + protected SkinData withModel(SkinModel model) { + if(model != null && skinModel != model) { + if(inverseModel == null) { + return inverseModel = new SkinData() { + @Override + public ResourceLocation getLocation() { + return skinLocation; + } + @Override + public SkinModel getModel() { + return model; + } + }; + } + return inverseModel; + }else { + return this; + } + } + + protected void handleSkinResultPreset(int skinID) { + DefaultSkins skin = DefaultSkins.getSkinFromId(skinID); + skinLocation = skin.location; + skinModel = skin.model; + state |= ServerTextureCacheOld.STATE_S_LOADED; + } + + protected void handleSkinResultCustomV4(byte[] customSkin, int modelID) { + handleSkinResultCustomV3(SkinPacketVersionCache.convertToV3Raw(customSkin), modelID); + } + + protected void handleSkinResultCustomV3(byte[] customSkin, int modelID) { + if(modelID != 0xFF) { + skinModel = SkinModel.getSanitizedModelFromId(modelID); + }else if(skinModel == null) { + skinModel = SkinModel.STEVE; + } + skinTexture = new EaglerSkinTexture(customSkin, skinModel.width, skinModel.height); + state |= ServerTextureCacheOld.STATE_S_COMPLETE; + } + + protected void loadSkin(TextureManager textureManager) { + skinLocation = new ResourceLocation("eagler:multiplayer/tex_" + ServerTextureCacheOld.texId++); + textureManager.loadTexture(skinLocation, skinTexture); + state |= ServerTextureCacheOld.STATE_S_LOADED; + } + + protected void release(TextureManager textureManager) { + if(skinTexture != null && (state & ServerTextureCacheOld.STATE_S_LOADED) != 0) { + textureManager.deleteTexture(skinLocation); + } + } + +} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/PlayerTextureEntry.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/PlayerTextureEntry.java new file mode 100644 index 00000000..bd72359c --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/PlayerTextureEntry.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.skin_cache; + +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.profile.DefaultCapes; +import net.lax1dude.eaglercraft.v1_8.profile.DefaultSkins; +import net.lax1dude.eaglercraft.v1_8.profile.EaglerSkinTexture; +import net.lax1dude.eaglercraft.v1_8.profile.SkinConverter; +import net.lax1dude.eaglercraft.v1_8.profile.SkinModel; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.util.ResourceLocation; + +class PlayerTextureEntry extends SkinData { + + protected final EaglercraftUUID uuid; + + protected int state; + + protected long lastHit; + + protected ResourceLocation skinLocation; + protected EaglerSkinTexture skinTexture; + protected SkinModel skinModel; + + protected ResourceLocation capeLocation; + protected EaglerSkinTexture capeTexture; + + public PlayerTextureEntry(EaglercraftUUID uuid) { + this.uuid = uuid; + } + + @Override + public ResourceLocation getLocation() { + return skinLocation; + } + + @Override + public SkinModel getModel() { + return skinModel; + } + + protected void handleSkinResultPreset(int skinID) { + DefaultSkins skin = DefaultSkins.getSkinFromId(skinID); + skinLocation = skin.location; + skinModel = skin.model; + state |= ServerTextureCache.STATE_S_LOADED; + } + + protected void handleSkinResultCustomV4(byte[] customSkin, int modelID) { + handleSkinResultCustomV3(SkinPacketVersionCache.convertToV3Raw(customSkin), modelID); + } + + protected void handleSkinResultCustomV3(byte[] customSkin, int modelID) { + skinModel = SkinModel.getSanitizedModelFromId(modelID); + skinTexture = new EaglerSkinTexture(customSkin, skinModel.width, skinModel.height); + state |= ServerTextureCache.STATE_S_COMPLETE; + } + + protected void loadSkin(TextureManager textureManager) { + skinLocation = new ResourceLocation("eagler:multiplayer/tex_" + ServerTextureCache.texId++); + textureManager.loadTexture(skinLocation, skinTexture); + state |= ServerTextureCache.STATE_S_LOADED; + } + + protected void handleCapeResultPreset(int presetCape) { + DefaultCapes cape = DefaultCapes.getCapeFromId(presetCape); + capeLocation = cape.location; + state |= ServerTextureCache.STATE_C_LOADED; + } + + protected void handleCapeResultCustom(byte[] customCape) { + byte[] pixels32x32 = new byte[4096]; + SkinConverter.convertCape23x17RGBto32x32RGBA(customCape, pixels32x32); + capeTexture = new EaglerSkinTexture(pixels32x32, 32, 32); + state |= ServerTextureCache.STATE_C_COMPLETE; + } + + protected void loadCape(TextureManager textureManager) { + capeLocation = new ResourceLocation("eagler:multiplayer/tex_" + ServerTextureCache.texId++); + textureManager.loadTexture(capeLocation, capeTexture); + state |= ServerTextureCache.STATE_C_LOADED; + } + + protected void release(TextureManager textureManager) { + if(skinTexture != null && (state & ServerTextureCache.STATE_S_LOADED) != 0) { + textureManager.deleteTexture(skinLocation); + } + if(capeTexture != null && (state & ServerTextureCache.STATE_C_LOADED) != 0) { + textureManager.deleteTexture(capeLocation); + } + } + + protected void drop(TextureManager textureManager, boolean skin, boolean cape) { + if(skin) { + if(skinTexture != null && (state & ServerTextureCache.STATE_S_LOADED) != 0) { + textureManager.deleteTexture(skinLocation); + } + skinTexture = null; + skinLocation = null; + state &= ~(ServerTextureCache.STATE_S_PENDING | ServerTextureCache.STATE_S_LOADED + | ServerTextureCache.STATE_S_COMPLETE); + } + if(cape) { + if(capeTexture != null && (state & ServerTextureCache.STATE_C_LOADED) != 0) { + textureManager.deleteTexture(capeLocation); + } + capeTexture = null; + capeLocation = null; + state &= ~(ServerTextureCache.STATE_C_PENDING | ServerTextureCache.STATE_C_LOADED + | ServerTextureCache.STATE_C_COMPLETE); + } + } + +} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ServerTextureCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ServerTextureCache.java new file mode 100644 index 00000000..4125c247 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ServerTextureCache.java @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.skin_cache; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import com.carrotsearch.hppc.ObjectLongHashMap; +import com.carrotsearch.hppc.ObjectLongMap; + +import net.lax1dude.eaglercraft.v1_8.EagRuntime; +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile; +import net.lax1dude.eaglercraft.v1_8.mojang.authlib.TexturesProperty; +import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile; +import net.lax1dude.eaglercraft.v1_8.profile.SkinModel; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.StateFlags; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.util.ResourceLocation; + +public abstract class ServerTextureCache { + + static final int STATE_S_PENDING = 1; + + static final int STATE_C_PENDING = 2; + + static final int STATE_SC_PENDING = STATE_S_PENDING | STATE_C_PENDING; + + static final int STATE_S_COMPLETE = 4; + + static final int STATE_C_COMPLETE = 8; + + static final int STATE_S_LOADED = 16; + + static final int STATE_C_LOADED = 32; + + static int texId = 0; + + protected final int protocolVers; + protected final NetHandlerPlayClient netHandler; + protected final TextureManager textureManager; + protected final EaglercraftUUID self; + + private EaglercraftUUID mruPlayerKey = null; + private PlayerTextureEntry mruPlayerTexture = null; + private final Map playerTextures = new HashMap<>(256); + + private EaglercraftUUID mruForeignKey = null; + private ForeignTextureEntry mruForeignTexture = null; + private final Map foreignTextures = new HashMap<>(256); + + private final Set pendingPlayerToLookup = new HashSet<>(32); + private final Set pendingForeignToLookup = new HashSet<>(32); + private final ObjectLongMap evictedPlayers = new ObjectLongHashMap<>(32); + + private int nextFlush = 200; + private int nextEvictFlush = 20; + private int flush = 0; + + public static ServerTextureCache create(NetHandlerPlayClient netHandler, TextureManager textureManager) { + if (netHandler.getEaglerMessageProtocol().ver >= 5) { + return new ServerTextureCacheV5(netHandler, textureManager); + } else { + return new ServerTextureCacheOld(netHandler, textureManager); + } + } + + public ServerTextureCache(NetHandlerPlayClient netHandler, TextureManager textureManager) { + this.protocolVers = netHandler.getEaglerMessageProtocol().ver; + this.netHandler = netHandler; + this.textureManager = textureManager; + this.self = netHandler.getGameProfile().getId(); + } + + private PlayerTextureEntry loadPlayer(EaglercraftUUID uuid) { + if (mruPlayerKey != null && uuid.equals(mruPlayerKey)) { + return mruPlayerTexture; + } + PlayerTextureEntry ret = playerTextures.get(uuid); + if (ret == null) { + playerTextures.put(uuid, ret = new PlayerTextureEntry(uuid)); + } + ret.lastHit = EagRuntime.steadyTimeMillis(); + mruPlayerKey = uuid; + mruPlayerTexture = ret; + return ret; + } + + private ForeignTextureEntry loadForeign(EaglercraftUUID uuid, String url, SkinModel model) { + if (mruForeignKey != null && uuid.equals(mruForeignKey)) { + return mruForeignTexture; + } + ForeignTextureEntry ret = foreignTextures.get(uuid); + if (ret == null) { + foreignTextures.put(uuid, ret = new ForeignTextureEntry(uuid, url, model)); + } + ret.lastHit = EagRuntime.steadyTimeMillis(); + mruForeignKey = uuid; + mruForeignTexture = ret; + return ret; + } + + public SkinData getPlayerSkin(GameProfile profile) { + if (self.equals(profile.getId())) { + return SkinData.defaultSkinSelf; + } + TexturesProperty prop = profile.getTextures(); + if (prop.eaglerPlayer != (byte) 0) { + return getPlayerSkinImpl(profile, prop); + } else { + SkinData ret = getForeignSkinImpl(profile, prop); + if (ret != null) { + return ret; + } else if (StateFlags.eaglerPlayerFlag) { + return SkinData.getDefaultSkin(profile.getId()); + } else { + return getPlayerSkinImpl(profile, prop); + } + } + } + + private SkinData getPlayerSkinImpl(GameProfile profile, TexturesProperty prop) { + EaglercraftUUID uuid = profile.getId(); + if (checkEvicted(uuid)) { + return SkinData.getDefaultSkin(uuid); + } + PlayerTextureEntry etr = loadPlayer(uuid); + int state = etr.state; + if ((state & STATE_S_LOADED) != 0) { + return etr; + } else if ((state & STATE_S_COMPLETE) != 0) { + etr.loadSkin(textureManager); + return etr; + } else { + if ((state & STATE_S_PENDING) == 0) { + etr.state = (state | STATE_S_PENDING); + pendingPlayerToLookup.add(etr); + } + return SkinData.getDefaultSkin(profile.getId()); + } + } + + private SkinData getForeignSkinImpl(GameProfile profile, TexturesProperty prop) { + if(StateFlags.disableSkinURLLookup) { + return null; + } + String url = prop.skin; + if (url != null) { + ForeignTextureEntry etr = loadForeign(prop.loadSkinTextureUUID(), url, prop.model); + int state = etr.state; + if ((state & STATE_S_LOADED) != 0) { + return etr.withModel(prop.model); + } else if ((state & STATE_S_COMPLETE) != 0) { + etr.loadSkin(textureManager); + return etr.withModel(prop.model); + } else { + if ((state & STATE_S_PENDING) == 0) { + etr.state = (state | STATE_S_PENDING); + pendingForeignToLookup.add(etr); + } + return SkinData.getDefaultSkin(prop.model); + } + } + return null; + } + + public ResourceLocation getPlayerCape(GameProfile profile) { + EaglercraftUUID uuid = profile.getId(); + if (uuid.equals(self)) { + return EaglerProfile.getActiveCapeResourceLocation(); + } + if (!StateFlags.eaglerPlayerFlag || profile.getTextures().eaglerPlayer != (byte) 0) { + if (checkEvicted(uuid)) { + return null; + } + PlayerTextureEntry etr = loadPlayer(uuid); + int state = etr.state; + if ((state & STATE_C_LOADED) != 0) { + return etr.capeLocation; + } else if ((state & STATE_C_COMPLETE) != 0) { + etr.loadCape(textureManager); + return etr.capeLocation; + } else { + if ((state & STATE_C_PENDING) == 0) { + etr.state = (state | STATE_C_PENDING); + pendingPlayerToLookup.add(etr); + } + return null; + } + } + // Loading capes by URL is not currently supported + // (Should only affect NPCs on a working setup) + return null; + } + + public void dropPlayer(EaglercraftUUID playerUUID, boolean skin, boolean cape) { + if (skin || cape) { + PlayerTextureEntry etr = playerTextures.get(playerUUID); + if (etr != null) { + etr.drop(textureManager, skin, cape); + _dropPlayer(playerUUID, skin, cape); + } + } + } + + protected abstract void _dropPlayer(EaglercraftUUID playerUUID, boolean skin, boolean cape); + + public void evictPlayer(EaglercraftUUID playerUUID) { + PlayerTextureEntry etr = playerTextures.remove(playerUUID); + if (etr != null) { + etr.release(textureManager); + } + if (mruPlayerKey != null && playerUUID.equals(mruPlayerKey)) { + mruPlayerKey = null; + mruPlayerTexture = null; + } + evictedPlayers.put(playerUUID, EagRuntime.steadyTimeMillis() + 2000l); + } + + private boolean checkEvicted(EaglercraftUUID playerUUID) { + if (!evictedPlayers.isEmpty()) { + long l = evictedPlayers.getOrDefault(playerUUID, -1l); + return l != -1l && EagRuntime.steadyTimeMillis() < l; + } + return false; + } + + public void runTick() { + if (!pendingPlayerToLookup.isEmpty()) { + for (PlayerTextureEntry etr : pendingPlayerToLookup) { + int state = etr.state; + if (protocolVers >= 5 && (state & STATE_SC_PENDING) == STATE_SC_PENDING) { + sendTexturesRequest(etr); + } else { + if ((state & STATE_S_PENDING) != 0) { + sendSkinRequest(etr); + } + if ((state & STATE_C_PENDING) != 0) { + sendCapeRequest(etr); + } + } + } + pendingPlayerToLookup.clear(); + } + if (!pendingForeignToLookup.isEmpty()) { + for (ForeignTextureEntry etr : pendingForeignToLookup) { + if ((etr.state & STATE_S_PENDING) != 0) { + sendSkinRequest(etr); + } + } + pendingForeignToLookup.clear(); + } + if (--nextEvictFlush <= 0) { + nextEvictFlush = 20; + long now = EagRuntime.steadyTimeMillis(); + evictedPlayers.removeAll((obj, millis) -> { + return now > millis; + }); + } + if (--nextFlush <= 0) { + nextFlush = 200; + long now = EagRuntime.steadyTimeMillis(); + lookupFlush(now); + if ((++flush & 3) == 0) { + if (!playerTextures.isEmpty()) { + Iterator itr1 = playerTextures.values().iterator(); + while (itr1.hasNext()) { + PlayerTextureEntry etr = itr1.next(); + if (now - etr.lastHit > (900l * 1000l)) { + itr1.remove(); + etr.release(textureManager); + } + } + mruPlayerKey = null; + mruPlayerTexture = null; + } + if (!foreignTextures.isEmpty()) { + Iterator itr2 = foreignTextures.values().iterator(); + while (itr2.hasNext()) { + ForeignTextureEntry etr = itr2.next(); + if (now - etr.lastHit > (900l * 1000l)) { + itr2.remove(); + etr.release(textureManager); + } + } + mruForeignKey = null; + mruForeignTexture = null; + } + } + } + } + + public void destroy() { + if (!playerTextures.isEmpty()) { + for (PlayerTextureEntry etr : playerTextures.values()) { + etr.release(textureManager); + } + playerTextures.clear(); + mruPlayerKey = null; + mruPlayerTexture = null; + } + if (!foreignTextures.isEmpty()) { + for (ForeignTextureEntry etr : foreignTextures.values()) { + etr.release(textureManager); + } + foreignTextures.clear(); + mruForeignKey = null; + mruForeignTexture = null; + } + pendingPlayerToLookup.clear(); + pendingForeignToLookup.clear(); + evictedPlayers.clear(); + } + + protected abstract void lookupFlush(long now); + + protected abstract void sendTexturesRequest(PlayerTextureEntry etr); + + protected abstract void sendSkinRequest(PlayerTextureEntry etr); + + protected abstract void sendSkinRequest(ForeignTextureEntry etr); + + protected abstract void sendCapeRequest(PlayerTextureEntry etr); + + public abstract void handlePacket(SPacketOtherSkinPresetEAG packet); + + public abstract void handlePacket(SPacketOtherSkinPresetV5EAG packet); + + public abstract void handlePacket(SPacketOtherSkinCustomV3EAG packet); + + public abstract void handlePacket(SPacketOtherSkinCustomV4EAG packet); + + public abstract void handlePacket(SPacketOtherSkinCustomV5EAG packet); + + public abstract void handlePacket(SPacketOtherCapePresetEAG packet); + + public abstract void handlePacket(SPacketOtherCapePresetV5EAG packet); + + public abstract void handlePacket(SPacketOtherCapeCustomEAG packet); + + public abstract void handlePacket(SPacketOtherCapeCustomV5EAG packet); + + public abstract void handlePacket(SPacketOtherTexturesV5EAG packet); + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ServerTextureCacheOld.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ServerTextureCacheOld.java new file mode 100644 index 00000000..4cb70544 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ServerTextureCacheOld.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.skin_cache; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import net.lax1dude.eaglercraft.v1_8.EagRuntime; +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.client.renderer.texture.TextureManager; + +public class ServerTextureCacheOld extends ServerTextureCache { + + private static abstract class PendingLookup { + + protected final long expiresAt = EagRuntime.steadyTimeMillis() + (30l * 1000l); + + protected abstract void handleResult(GameMessagePacket packet); + + protected abstract void handleTimeout(); + + } + + private final Map pendingSkinLookup = new HashMap<>(64); + private final Map pendingCapeLookup = new HashMap<>(64); + + public ServerTextureCacheOld(NetHandlerPlayClient netHandler, TextureManager textureManager) { + super(netHandler, textureManager); + if(protocolVers > 4) { + throw new IllegalStateException(); + } + } + + @Override + protected void _dropPlayer(EaglercraftUUID playerUUID, boolean skin, boolean cape) { + if(skin) { + pendingSkinLookup.remove(playerUUID); + } + if(cape) { + pendingCapeLookup.remove(playerUUID); + } + } + + @Override + protected void sendSkinRequest(PlayerTextureEntry etr) { + pendingSkinLookup.put(etr.uuid, new PendingLookup() { + @Override + protected void handleResult(GameMessagePacket packet) { + etr.state &= ~STATE_S_PENDING; + if(packet instanceof SPacketOtherSkinPresetEAG) { + SPacketOtherSkinPresetEAG pkt = (SPacketOtherSkinPresetEAG) packet; + etr.handleSkinResultPreset(pkt.presetSkin); + }else if(packet instanceof SPacketOtherSkinCustomV4EAG) { + SPacketOtherSkinCustomV4EAG pkt = (SPacketOtherSkinCustomV4EAG) packet; + etr.handleSkinResultCustomV4(pkt.customSkin, pkt.modelID); + }else if(packet instanceof SPacketOtherSkinCustomV3EAG) { + SPacketOtherSkinCustomV3EAG pkt = (SPacketOtherSkinCustomV3EAG) packet; + etr.handleSkinResultCustomV3(pkt.customSkin, pkt.modelID); + }else { + throw new IllegalStateException(); + } + } + @Override + protected void handleTimeout() { + etr.state &= ~STATE_S_PENDING; + } + }); + netHandler.sendEaglerMessage(new CPacketGetOtherSkinEAG(etr.uuid.getMostSignificantBits(), + etr.uuid.getLeastSignificantBits())); + } + + @Override + protected void sendCapeRequest(PlayerTextureEntry etr) { + pendingCapeLookup.put(etr.uuid, new PendingLookup() { + @Override + protected void handleResult(GameMessagePacket packet) { + etr.state &= ~STATE_C_PENDING; + if(packet instanceof SPacketOtherCapePresetEAG) { + SPacketOtherCapePresetEAG pkt = (SPacketOtherCapePresetEAG) packet; + etr.handleCapeResultPreset(pkt.presetCape); + }else if(packet instanceof SPacketOtherCapeCustomEAG) { + SPacketOtherCapeCustomEAG pkt = (SPacketOtherCapeCustomEAG) packet; + etr.handleCapeResultCustom(pkt.customCape); + }else { + throw new IllegalStateException(); + } + } + @Override + protected void handleTimeout() { + etr.state &= ~STATE_C_PENDING; + } + }); + netHandler.sendEaglerMessage(new CPacketGetOtherCapeEAG(etr.uuid.getMostSignificantBits(), + etr.uuid.getLeastSignificantBits())); + } + + @Override + protected void sendSkinRequest(ForeignTextureEntry etr) { + pendingSkinLookup.put(etr.uuid, new PendingLookup() { + @Override + protected void handleResult(GameMessagePacket packet) { + etr.state &= ~STATE_S_PENDING; + if(packet instanceof SPacketOtherSkinPresetEAG) { + SPacketOtherSkinPresetEAG pkt = (SPacketOtherSkinPresetEAG) packet; + etr.handleSkinResultPreset(pkt.presetSkin); + }else if(packet instanceof SPacketOtherSkinCustomV4EAG) { + SPacketOtherSkinCustomV4EAG pkt = (SPacketOtherSkinCustomV4EAG) packet; + etr.handleSkinResultCustomV4(pkt.customSkin, pkt.modelID); + }else if(packet instanceof SPacketOtherSkinCustomV3EAG) { + SPacketOtherSkinCustomV3EAG pkt = (SPacketOtherSkinCustomV3EAG) packet; + etr.handleSkinResultCustomV3(pkt.customSkin, pkt.modelID); + }else { + throw new IllegalStateException(); + } + } + @Override + protected void handleTimeout() { + etr.state &= ~STATE_S_PENDING; + } + }); + netHandler.sendEaglerMessage(new CPacketGetSkinByURLEAG(etr.uuid.getMostSignificantBits(), + etr.uuid.getLeastSignificantBits(), etr.url)); + } + + @Override + protected void sendTexturesRequest(PlayerTextureEntry etr) { + throw new IllegalStateException(); + } + + @Override + protected void lookupFlush(long now) { + lookupFlush(pendingSkinLookup, now); + lookupFlush(pendingCapeLookup, now); + } + + private void lookupFlush(Map pending, long now) { + if(!pending.isEmpty()) { + Iterator itr1 = pending.values().iterator(); + while(itr1.hasNext()) { + PendingLookup etr = itr1.next(); + if(now > etr.expiresAt) { + itr1.remove(); + etr.handleTimeout(); + } + } + } + } + + @Override + public void handlePacket(SPacketOtherSkinPresetEAG packet) { + PendingLookup lookup = pendingSkinLookup.remove(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); + if(lookup != null) { + lookup.handleResult(packet); + } + } + + @Override + public void handlePacket(SPacketOtherSkinPresetV5EAG packet) { + throw new IllegalStateException(); + } + + @Override + public void handlePacket(SPacketOtherSkinCustomV3EAG packet) { + PendingLookup lookup = pendingSkinLookup.remove(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); + if(lookup != null) { + lookup.handleResult(packet); + } + } + + @Override + public void handlePacket(SPacketOtherSkinCustomV4EAG packet) { + PendingLookup lookup = pendingSkinLookup.remove(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); + if(lookup != null) { + lookup.handleResult(packet); + } + } + + @Override + public void handlePacket(SPacketOtherSkinCustomV5EAG packet) { + throw new IllegalStateException(); + } + + @Override + public void handlePacket(SPacketOtherCapePresetEAG packet) { + PendingLookup lookup = pendingCapeLookup.remove(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); + if(lookup != null) { + lookup.handleResult(packet); + } + } + + @Override + public void handlePacket(SPacketOtherCapePresetV5EAG packet) { + throw new IllegalStateException(); + } + + @Override + public void handlePacket(SPacketOtherCapeCustomEAG packet) { + PendingLookup lookup = pendingCapeLookup.remove(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); + if(lookup != null) { + lookup.handleResult(packet); + } + } + + @Override + public void handlePacket(SPacketOtherCapeCustomV5EAG packet) { + throw new IllegalStateException(); + } + + @Override + public void handlePacket(SPacketOtherTexturesV5EAG packet) { + throw new IllegalStateException(); + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ServerTextureCacheV5.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ServerTextureCacheV5.java new file mode 100644 index 00000000..f3323f42 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/ServerTextureCacheV5.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.skin_cache; + +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.predicates.IntObjectPredicate; + +import net.lax1dude.eaglercraft.v1_8.EagRuntime; +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.client.renderer.texture.TextureManager; + +public class ServerTextureCacheV5 extends ServerTextureCache { + + private static abstract class PendingLookup { + + protected final EaglercraftUUID uuid; + protected final long expiresAt = EagRuntime.steadyTimeMillis() + (30l * 1000l); + + protected PendingLookup(EaglercraftUUID uuid) { + this.uuid = uuid; + } + + protected abstract void handleResult(GameMessagePacket packet); + + protected abstract void handleTimeout(); + + } + + private final IntObjectMap pendingSkinLookup = new IntObjectHashMap<>(64); + private final IntObjectMap pendingCapeLookup = new IntObjectHashMap<>(64); + private final IntObjectMap pendingTextureLookup = new IntObjectHashMap<>(64); + + private int lookupIdA = 0; + private int lookupIdB = 0; + private int lookupIdC = 0; + + public ServerTextureCacheV5(NetHandlerPlayClient netHandler, TextureManager textureManager) { + super(netHandler, textureManager); + } + + private int nextLookupIdA() { + return lookupIdA = (lookupIdA + 1) & 0x3FFF; + } + + private int nextLookupIdB() { + return lookupIdB = (lookupIdB + 1) & 0x3FFF; + } + + private int nextLookupIdC() { + return lookupIdC = (lookupIdC + 1) & 0x3FFF; + } + + @Override + protected void sendSkinRequest(PlayerTextureEntry etr) { + int lookupId = nextLookupIdA(); + pendingSkinLookup.put(lookupId, new PendingLookup(etr.uuid) { + @Override + protected void handleResult(GameMessagePacket packet) { + etr.state &= ~STATE_S_PENDING; + if(packet instanceof SPacketOtherSkinPresetV5EAG) { + SPacketOtherSkinPresetV5EAG pkt = (SPacketOtherSkinPresetV5EAG) packet; + etr.handleSkinResultPreset(pkt.presetSkin); + }else if(packet instanceof SPacketOtherSkinCustomV5EAG) { + SPacketOtherSkinCustomV5EAG pkt = (SPacketOtherSkinCustomV5EAG) packet; + etr.handleSkinResultCustomV4(pkt.customSkin, pkt.modelID); + }else { + throw new IllegalStateException(); + } + } + @Override + protected void handleTimeout() { + etr.state &= ~STATE_S_PENDING; + } + }); + netHandler.sendEaglerMessage(new CPacketGetOtherSkinV5EAG(lookupId, etr.uuid.getMostSignificantBits(), + etr.uuid.getLeastSignificantBits())); + } + + @Override + protected void sendCapeRequest(PlayerTextureEntry etr) { + int lookupId = nextLookupIdB(); + pendingCapeLookup.put(lookupId, new PendingLookup(etr.uuid) { + @Override + protected void handleResult(GameMessagePacket packet) { + etr.state &= ~STATE_C_PENDING; + if(packet instanceof SPacketOtherCapePresetV5EAG) { + SPacketOtherCapePresetV5EAG pkt = (SPacketOtherCapePresetV5EAG) packet; + etr.handleCapeResultPreset(pkt.presetCape); + }else if(packet instanceof SPacketOtherCapeCustomV5EAG) { + SPacketOtherCapeCustomV5EAG pkt = (SPacketOtherCapeCustomV5EAG) packet; + etr.handleCapeResultCustom(pkt.customCape); + }else { + throw new IllegalStateException(); + } + } + @Override + protected void handleTimeout() { + etr.state &= ~STATE_C_PENDING; + } + }); + netHandler.sendEaglerMessage(new CPacketGetOtherCapeV5EAG(lookupId, etr.uuid.getMostSignificantBits(), + etr.uuid.getLeastSignificantBits())); + } + + @Override + protected void sendSkinRequest(ForeignTextureEntry etr) { + int lookupId = nextLookupIdA(); + pendingSkinLookup.put(lookupId, new PendingLookup(null) { + @Override + protected void handleResult(GameMessagePacket packet) { + etr.state &= ~STATE_S_PENDING; + if(packet instanceof SPacketOtherSkinPresetV5EAG) { + SPacketOtherSkinPresetV5EAG pkt = (SPacketOtherSkinPresetV5EAG) packet; + etr.handleSkinResultPreset(pkt.presetSkin); + }else if(packet instanceof SPacketOtherSkinCustomV5EAG) { + SPacketOtherSkinCustomV5EAG pkt = (SPacketOtherSkinCustomV5EAG) packet; + etr.handleSkinResultCustomV4(pkt.customSkin, pkt.modelID); + }else { + throw new IllegalStateException(); + } + } + @Override + protected void handleTimeout() { + etr.state &= ~STATE_S_PENDING; + } + }); + netHandler.sendEaglerMessage(new CPacketGetSkinByURLV5EAG(lookupId, etr.url)); + } + + @Override + protected void sendTexturesRequest(PlayerTextureEntry etr) { + int lookupId = nextLookupIdC(); + pendingTextureLookup.put(lookupId, new PendingLookup(etr.uuid) { + @Override + protected void handleResult(GameMessagePacket packet) { + etr.state &= ~STATE_SC_PENDING; + if(packet instanceof SPacketOtherTexturesV5EAG) { + SPacketOtherTexturesV5EAG pkt = (SPacketOtherTexturesV5EAG) packet; + if(pkt.skinID >= 0) { + etr.handleSkinResultPreset(pkt.skinID); + }else { + etr.handleSkinResultCustomV4(pkt.customSkin, -pkt.skinID - 1); + } + if(pkt.capeID >= 0) { + etr.handleCapeResultPreset(pkt.capeID); + }else { + etr.handleCapeResultCustom(pkt.customCape); + } + }else { + throw new IllegalStateException(); + } + } + @Override + protected void handleTimeout() { + etr.state &= ~STATE_SC_PENDING; + } + }); + netHandler.sendEaglerMessage(new CPacketGetOtherTexturesV5EAG(lookupId, etr.uuid.getMostSignificantBits(), + etr.uuid.getLeastSignificantBits())); + } + + @Override + protected void _dropPlayer(EaglercraftUUID playerUUID, boolean skin, boolean cape) { + IntObjectPredicate pred = (i, o) -> { + return o.uuid != null && playerUUID.equals(o.uuid); + }; + if(skin) { + pendingSkinLookup.removeAll(pred); + } + if(cape) { + pendingCapeLookup.removeAll(pred); + } + pendingTextureLookup.removeAll(pred); + } + + @Override + protected void lookupFlush(long now) { + IntObjectPredicate pred = (i, o) -> { + return now > o.expiresAt; + }; + pendingSkinLookup.removeAll(pred); + pendingCapeLookup.removeAll(pred); + pendingTextureLookup.removeAll(pred); + } + + @Override + public void handlePacket(SPacketOtherSkinPresetEAG packet) { + throw new IllegalStateException(); + } + + @Override + public void handlePacket(SPacketOtherSkinPresetV5EAG packet) { + PendingLookup lookup = pendingSkinLookup.remove(packet.requestId); + if(lookup != null) { + lookup.handleResult(packet); + } + } + + @Override + public void handlePacket(SPacketOtherSkinCustomV3EAG packet) { + throw new IllegalStateException(); + } + + @Override + public void handlePacket(SPacketOtherSkinCustomV4EAG packet) { + throw new IllegalStateException(); + } + + @Override + public void handlePacket(SPacketOtherSkinCustomV5EAG packet) { + PendingLookup lookup = pendingSkinLookup.remove(packet.requestId); + if(lookup != null) { + lookup.handleResult(packet); + } + } + + @Override + public void handlePacket(SPacketOtherCapePresetEAG packet) { + throw new IllegalStateException(); + } + + @Override + public void handlePacket(SPacketOtherCapePresetV5EAG packet) { + PendingLookup lookup = pendingCapeLookup.remove(packet.requestId); + if(lookup != null) { + lookup.handleResult(packet); + } + } + + @Override + public void handlePacket(SPacketOtherCapeCustomEAG packet) { + throw new IllegalStateException(); + } + + @Override + public void handlePacket(SPacketOtherCapeCustomV5EAG packet) { + PendingLookup lookup = pendingCapeLookup.remove(packet.requestId); + if(lookup != null) { + lookup.handleResult(packet); + } + } + + @Override + public void handlePacket(SPacketOtherTexturesV5EAG packet) { + PendingLookup lookup = pendingTextureLookup.remove(packet.requestId); + if(lookup != null) { + lookup.handleResult(packet); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/SkinData.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/SkinData.java new file mode 100644 index 00000000..e6bb321b --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/skin_cache/SkinData.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.skin_cache; + +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.profile.DefaultSkins; +import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile; +import net.lax1dude.eaglercraft.v1_8.profile.SkinModel; +import net.minecraft.util.ResourceLocation; + +public abstract class SkinData { + + public abstract ResourceLocation getLocation(); + + public abstract SkinModel getModel(); + + static SkinData getDefaultSkin(EaglercraftUUID uuid) { + return (uuid != null && (uuid.hashCode() & 1) != 0) ? defaultSkinDataAlex : defaultSkinDataSteve; + } + + static SkinData getDefaultSkin(SkinModel model) { + return (model == SkinModel.ALEX) ? defaultSkinDataAlex : defaultSkinDataSteve; + } + + static final SkinData defaultSkinDataSteve = new SkinData() { + @Override + public ResourceLocation getLocation() { + return DefaultSkins.DEFAULT_STEVE.location; + } + @Override + public SkinModel getModel() { + return SkinModel.STEVE; + } + }; + + static final SkinData defaultSkinDataAlex = new SkinData() { + @Override + public ResourceLocation getLocation() { + return DefaultSkins.DEFAULT_ALEX.location; + } + @Override + public SkinModel getModel() { + return SkinModel.ALEX; + } + }; + + static final SkinData defaultSkinSelf = new SkinData() { + @Override + public ResourceLocation getLocation() { + return EaglerProfile.getActiveSkinResourceLocation(); + } + @Override + public SkinModel getModel() { + return EaglerProfile.getActiveSkinModel(); + } + }; + +} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ConnectionHandshake.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ConnectionHandshake.java deleted file mode 100644 index 339f8eea..00000000 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ConnectionHandshake.java +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -package net.lax1dude.eaglercraft.v1_8.socket; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import net.lax1dude.eaglercraft.v1_8.ArrayUtils; -import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache; -import net.lax1dude.eaglercraft.v1_8.EagRuntime; -import net.lax1dude.eaglercraft.v1_8.EagUtils; -import net.lax1dude.eaglercraft.v1_8.EaglerInputStream; -import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream; -import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; -import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion; -import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState; -import net.lax1dude.eaglercraft.v1_8.crypto.SHA256Digest; -import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient; -import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame; -import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; -import net.lax1dude.eaglercraft.v1_8.log4j.Logger; -import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile; -import net.lax1dude.eaglercraft.v1_8.profile.GuiAuthenticationScreen; -import net.lax1dude.eaglercraft.v1_8.update.UpdateService; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiDisconnected; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.multiplayer.GuiConnecting; -import net.minecraft.util.ChatComponentText; -import net.minecraft.util.EnumChatFormatting; -import net.minecraft.util.IChatComponent; - -public class ConnectionHandshake { - - private static final long baseTimeout = 10000l; - - private static final int protocolV2 = 2; - private static final int protocolV3 = 3; - private static final int protocolV4 = 4; - - private static final Logger logger = LogManager.getLogger(); - - public static String pluginVersion = null; - public static String pluginBrand = null; - public static int protocolVersion = -1; - - public static byte[] getSPHandshakeProtocolData() { - try { - EaglerOutputStream bao = new EaglerOutputStream(); - DataOutputStream d = new DataOutputStream(bao); - d.writeShort(3); // supported eagler protocols count - d.writeShort(protocolV2); // client supports v2 - d.writeShort(protocolV3); // client supports v3 - d.writeShort(protocolV4); // client supports v4 - return bao.toByteArray(); - }catch(IOException ex) { - throw new RuntimeException(ex); - } - } - - public static boolean attemptHandshake(Minecraft mc, IWebSocketClient client, GuiConnecting connecting, - GuiScreen ret, String password, boolean allowPlaintext, boolean enableCookies, byte[] cookieData) { - try { - EaglerProfile.clearServerSkinOverride(); - PauseMenuCustomizeState.reset(); - ClientUUIDLoadingCache.resetFlags(); - pluginVersion = null; - pluginBrand = null; - protocolVersion = -1; - EaglerOutputStream bao = new EaglerOutputStream(); - DataOutputStream d = new DataOutputStream(bao); - - d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_VERSION); - - d.writeByte(2); // legacy protocol version - - d.write(getSPHandshakeProtocolData()); // write supported eagler protocol versions - - d.writeShort(1); // supported game protocols count - d.writeShort(47); // client supports 1.8 protocol - - String clientBrand = EaglercraftVersion.projectForkName; - d.writeByte(clientBrand.length()); - d.writeBytes(clientBrand); - - String clientVers = EaglercraftVersion.projectOriginVersion; - d.writeByte(clientVers.length()); - d.writeBytes(clientVers); - - d.writeBoolean(password != null); - - String username = mc.getSession().getProfile().getName(); - d.writeByte(username.length()); - d.writeBytes(username); - - client.send(bao.toByteArray()); - - byte[] read = awaitNextPacket(client, baseTimeout); - if(read == null) { - logger.error("Read timed out while waiting for server protocol response!"); - return false; - } - - DataInputStream di = new DataInputStream(new EaglerInputStream(read)); - - int type = di.read(); - if(type == HandshakePacketTypes.PROTOCOL_VERSION_MISMATCH) { - - StringBuilder protocols = new StringBuilder(); - int c = di.readShort(); - for(int i = 0; i < c; ++i) { - if(i > 0) { - protocols.append(", "); - } - protocols.append("v").append(di.readShort()); - } - - StringBuilder games = new StringBuilder(); - c = di.readShort(); - for(int i = 0; i < c; ++i) { - if(i > 0) { - games.append(", "); - } - games.append("mc").append(di.readShort()); - } - - logger.info("Incompatible client: v2/v3/v4 & mc47"); - logger.info("Server supports: {}", protocols); - logger.info("Server supports: {}", games); - - int msgLen = di.read(); - byte[] dat = new byte[msgLen]; - di.read(dat); - String msg = new String(dat, StandardCharsets.UTF_8); - - mc.displayGuiScreen(new GuiDisconnected(ret, "connect.failed", new ChatComponentText(msg))); - - return false; - }else if(type == HandshakePacketTypes.PROTOCOL_SERVER_VERSION) { - protocolVersion = di.readShort(); - - if(protocolVersion != protocolV2 && protocolVersion != protocolV3 && protocolVersion != protocolV4) { - logger.info("Incompatible server version: {}", protocolVersion); - mc.displayGuiScreen(new GuiDisconnected(ret, "connect.failed", new ChatComponentText(protocolVersion < protocolV2 ? "Outdated Server" : "Outdated Client"))); - return false; - } - - int gameVers = di.readShort(); - if(gameVers != 47) { - logger.info("Incompatible minecraft protocol version: {}", gameVers); - mc.displayGuiScreen(new GuiDisconnected(ret, "connect.failed", new ChatComponentText("This server does not support 1.8!"))); - return false; - } - - logger.info("Server protocol: {}", protocolVersion); - - int msgLen = di.read(); - byte[] dat = new byte[msgLen]; - di.read(dat); - pluginBrand = ArrayUtils.asciiString(dat); - - msgLen = di.read(); - dat = new byte[msgLen]; - di.read(dat); - pluginVersion = ArrayUtils.asciiString(dat); - - logger.info("Server version: {}", pluginVersion); - logger.info("Server brand: {}", pluginBrand); - - int authType = di.read(); - int saltLength = (int)di.readShort() & 0xFFFF; - - byte[] salt = new byte[saltLength]; - di.read(salt); - - bao.reset(); - d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_REQUEST_LOGIN); - - d.writeByte(username.length()); - d.writeBytes(username); - - String requestedServer = "default"; - d.writeByte(requestedServer.length()); - d.writeBytes(requestedServer); - - if(authType != 0 && password != null && password.length() > 0) { - if(authType == HandshakePacketTypes.AUTH_METHOD_PLAINTEXT) { - if(allowPlaintext) { - logger.warn("Server is using insecure plaintext authentication"); - d.writeByte(password.length() << 1); - d.writeChars(password); - }else { - logger.error("Plaintext authentication was attempted but no user confirmation has been given to proceed"); - mc.displayGuiScreen(new GuiDisconnected(ret, "connect.failed", - new ChatComponentText(EnumChatFormatting.RED + "Plaintext authentication was attempted but no user confirmation has been given to proceed"))); - return false; - } - }else if(authType == HandshakePacketTypes.AUTH_METHOD_EAGLER_SHA256) { - SHA256Digest digest = new SHA256Digest(); - - int passLen = password.length(); - - digest.update((byte)((passLen >>> 8) & 0xFF)); - digest.update((byte)(passLen & 0xFF)); - - for(int i = 0; i < passLen; ++i) { - char codePoint = password.charAt(i); - digest.update((byte)((codePoint >>> 8) & 0xFF)); - digest.update((byte)(codePoint & 0xFF)); - } - - digest.update(HandshakePacketTypes.EAGLER_SHA256_SALT_SAVE, 0, 32); - - byte[] hashed = new byte[32]; - digest.doFinal(hashed, 0); - - digest.reset(); - - digest.update(hashed, 0, 32); - digest.update(salt, 0, 32); - digest.update(HandshakePacketTypes.EAGLER_SHA256_SALT_BASE, 0, 32); - - digest.doFinal(hashed, 0); - - digest.reset(); - - digest.update(hashed, 0, 32); - digest.update(salt, 32, 32); - digest.update(HandshakePacketTypes.EAGLER_SHA256_SALT_BASE, 0, 32); - - digest.doFinal(hashed, 0); - - d.writeByte(32); - d.write(hashed); - }else if(authType == HandshakePacketTypes.AUTH_METHOD_AUTHME_SHA256) { - SHA256Digest digest = new SHA256Digest(); - - byte[] passwd = password.getBytes(StandardCharsets.UTF_8); - digest.update(passwd, 0, passwd.length); - - byte[] hashed = new byte[32]; - digest.doFinal(hashed, 0); - - byte[] toHexAndSalt = new byte[64]; - for(int i = 0; i < 32; ++i) { - toHexAndSalt[i << 1] = HEX[(hashed[i] >> 4) & 0xF]; - toHexAndSalt[(i << 1) + 1] = HEX[hashed[i] & 0xF]; - } - - digest.reset(); - digest.update(toHexAndSalt, 0, 64); - digest.update(salt, 0, salt.length); - - digest.doFinal(hashed, 0); - - for(int i = 0; i < 32; ++i) { - toHexAndSalt[i << 1] = HEX[(hashed[i] >> 4) & 0xF]; - toHexAndSalt[(i << 1) + 1] = HEX[hashed[i] & 0xF]; - } - - d.writeByte(64); - d.write(toHexAndSalt); - }else { - logger.error("Unsupported authentication type: {}", authType); - mc.displayGuiScreen(new GuiDisconnected(ret, "connect.failed", - new ChatComponentText(EnumChatFormatting.RED + "Unsupported authentication type: " + authType + "\n\n" + EnumChatFormatting.GRAY + "(Use a newer version of the client)"))); - return false; - } - }else { - d.writeByte(0); - } - if(protocolVersion >= protocolV4) { - d.writeBoolean(enableCookies); - if(enableCookies && cookieData != null) { - d.writeByte(cookieData.length); - d.write(cookieData); - }else { - d.writeByte(0); - } - } - - client.send(bao.toByteArray()); - - read = awaitNextPacket(client, baseTimeout); - if(read == null) { - logger.error("Read timed out while waiting for login negotiation response!"); - return false; - } - - di = new DataInputStream(new EaglerInputStream(read)); - type = di.read(); - if(type == HandshakePacketTypes.PROTOCOL_SERVER_ALLOW_LOGIN) { - msgLen = di.read(); - dat = new byte[msgLen]; - di.read(dat); - - String serverUsername = ArrayUtils.asciiString(dat); - - Minecraft.getMinecraft().getSession().update(serverUsername, new EaglercraftUUID(di.readLong(), di.readLong())); - - Map profileDataToSend = new HashMap<>(); - - if(protocolVersion >= 4) { - bao.reset(); - d.writeLong(EaglercraftVersion.clientBrandUUID.msb); - d.writeLong(EaglercraftVersion.clientBrandUUID.lsb); - profileDataToSend.put("brand_uuid_v1", bao.toByteArray()); - } - - byte[] packetSkin = EaglerProfile.getSkinPacket(protocolVersion); - if(packetSkin.length > 0xFFFF) { - throw new IOException("Skin packet is too long: " + packetSkin.length); - } - profileDataToSend.put(protocolVersion >= 4 ? "skin_v2" : "skin_v1", packetSkin); - - byte[] packetCape = EaglerProfile.getCapePacket(); - if(packetCape.length > 0xFFFF) { - throw new IOException("Cape packet is too long: " + packetCape.length); - } - profileDataToSend.put("cape_v1", packetCape); - - byte[] packetSignatureData = UpdateService.getClientSignatureData(); - if(packetSignatureData != null) { - profileDataToSend.put("update_cert_v1", packetSignatureData); - } - - if(protocolVersion >= 4) { - List> toSend = new ArrayList<>(profileDataToSend.entrySet()); - while(!toSend.isEmpty()) { - int sendLen = 2; - bao.reset(); - d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_PROFILE_DATA); - d.writeByte(0); // will be replaced - int packetCount = 0; - while(!toSend.isEmpty() && packetCount < 255) { - Entry etr = toSend.get(toSend.size() - 1); - int i = 3 + etr.getKey().length() + etr.getValue().length; - if(sendLen + i < 0xFF00) { - String profileDataType = etr.getKey(); - d.writeByte(profileDataType.length()); - d.writeBytes(profileDataType); - byte[] data = etr.getValue(); - d.writeShort(data.length); - d.write(data); - toSend.remove(toSend.size() - 1); - ++packetCount; - }else { - break; - } - } - byte[] send = bao.toByteArray(); - send[1] = (byte)packetCount; - client.send(send); - } - }else { - for(Entry etr : profileDataToSend.entrySet()) { - bao.reset(); - d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_PROFILE_DATA); - String profileDataType = etr.getKey(); - d.writeByte(profileDataType.length()); - d.writeBytes(profileDataType); - byte[] data = etr.getValue(); - d.writeShort(data.length); - d.write(data); - client.send(bao.toByteArray()); - } - } - - bao.reset(); - d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_FINISH_LOGIN); - client.send(bao.toByteArray()); - - read = awaitNextPacket(client, baseTimeout); - if(read == null) { - logger.error("Read timed out while waiting for login confirmation response!"); - return false; - } - - di = new DataInputStream(new EaglerInputStream(read)); - type = di.read(); - if(type == HandshakePacketTypes.PROTOCOL_SERVER_FINISH_LOGIN) { - return true; - }else if(type == HandshakePacketTypes.PROTOCOL_SERVER_ERROR) { - showError(mc, client, connecting, ret, di, protocolVersion == protocolV2); - return false; - }else { - return false; - } - }else if(type == HandshakePacketTypes.PROTOCOL_SERVER_DENY_LOGIN) { - if(protocolVersion == protocolV2) { - msgLen = di.read(); - }else { - msgLen = di.readUnsignedShort(); - } - dat = new byte[msgLen]; - di.read(dat); - String errStr = new String(dat, StandardCharsets.UTF_8); - mc.displayGuiScreen(new GuiDisconnected(ret, "connect.failed", IChatComponent.Serializer.jsonToComponent(errStr))); - return false; - }else if(type == HandshakePacketTypes.PROTOCOL_SERVER_ERROR) { - showError(mc, client, connecting, ret, di, protocolVersion == protocolV2); - return false; - }else { - return false; - } - }else if(type == HandshakePacketTypes.PROTOCOL_SERVER_ERROR) { - showError(mc, client, connecting, ret, di, true); - return false; - }else { - return false; - } - }catch(Throwable t) { - logger.error("Exception in handshake"); - logger.error(t); - return false; - } - - } - - private static byte[] awaitNextPacket(IWebSocketClient client, long timeout) { - long millis = EagRuntime.steadyTimeMillis(); - IWebSocketFrame b; - while((b = client.getNextBinaryFrame()) == null) { - if(client.getState().isClosed()) { - return null; - } - EagUtils.sleep(50); - if(EagRuntime.steadyTimeMillis() - millis > timeout) { - client.close(); - return null; - } - } - return b.getByteArray(); - } - - private static void showError(Minecraft mc, IWebSocketClient client, GuiConnecting connecting, GuiScreen scr, DataInputStream err, boolean v2) throws IOException { - int errorCode = err.read(); - int msgLen = v2 ? err.read() : err.readUnsignedShort(); - - // workaround for bug in EaglerXBungee 1.2.7 and below - if(msgLen == 0) { - if(v2) { - if(err.available() == 256) { - msgLen = 256; - } - }else { - if(err.available() == 65536) { - msgLen = 65536; - } - } - } - - byte[] dat = new byte[msgLen]; - err.read(dat); - String errStr = new String(dat, StandardCharsets.UTF_8); - logger.info("Server Error Code {}: {}", errorCode, errStr); - if(errorCode == HandshakePacketTypes.SERVER_ERROR_RATELIMIT_BLOCKED) { - RateLimitTracker.registerBlock(client.getCurrentURI()); - mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(scr)); - }else if(errorCode == HandshakePacketTypes.SERVER_ERROR_RATELIMIT_LOCKED) { - RateLimitTracker.registerLockOut(client.getCurrentURI()); - mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(scr)); - }else if(errorCode == HandshakePacketTypes.SERVER_ERROR_CUSTOM_MESSAGE) { - mc.displayGuiScreen(new GuiDisconnected(scr, "connect.failed", IChatComponent.Serializer.jsonToComponent(errStr))); - }else if(connecting != null && errorCode == HandshakePacketTypes.SERVER_ERROR_AUTHENTICATION_REQUIRED) { - mc.displayGuiScreen(new GuiAuthenticationScreen(connecting, scr, errStr)); - }else { - mc.displayGuiScreen(new GuiDisconnected(scr, "connect.failed", new ChatComponentText("Server Error Code " + errorCode + "\n" + errStr))); - } - } - - public static GuiScreen displayAuthProtocolConfirm(int protocol, GuiScreen no, GuiScreen yes) { - if(protocol == HandshakePacketTypes.AUTH_METHOD_PLAINTEXT) { - return new GuiHandshakeApprove("plaintext", no, yes); - }else if(protocol != HandshakePacketTypes.AUTH_METHOD_EAGLER_SHA256 && protocol != HandshakePacketTypes.AUTH_METHOD_AUTHME_SHA256) { - return new GuiHandshakeApprove("unsupportedAuth", no); - }else { - return null; - } - } - - private static final byte[] HEX = new byte[] { - (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', - (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f' - }; -} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/EaglercraftNetworkManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/EaglercraftNetworkManager.java index 256a47d5..6e758311 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/EaglercraftNetworkManager.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/EaglercraftNetworkManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -22,6 +22,8 @@ import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake.ServerCapabilities; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.message.InjectedMessageController; import net.minecraft.network.EnumConnectionState; import net.minecraft.network.INetHandler; import net.minecraft.network.Packet; @@ -38,6 +40,9 @@ public abstract class EaglercraftNetworkManager { protected String pluginBrand = null; protected String pluginVersion = null; + protected InjectedMessageController injectedController = null; + + protected ServerCapabilities serverCapabilities = null; public static final Logger logger = LogManager.getLogger("NetworkManager"); @@ -45,10 +50,17 @@ public abstract class EaglercraftNetworkManager { this.address = address; this.temporaryBuffer = new PacketBuffer(Unpooled.buffer(0x1FFFF)); } - - public void setPluginInfo(String pluginBrand, String pluginVersion) { + + public void setPluginInfo(String pluginBrand, String pluginVersion, ServerCapabilities serverCapabilities) { this.pluginBrand = pluginBrand; this.pluginVersion = pluginVersion; + this.serverCapabilities = serverCapabilities; + } + + public void setLANInfo(int protocolVer) { + this.pluginBrand = "integrated"; + this.pluginVersion = "v" + protocolVer; + this.serverCapabilities = ServerCapabilities.getLAN(); } public String getPluginBrand() { @@ -59,6 +71,14 @@ public abstract class EaglercraftNetworkManager { return pluginVersion; } + public ServerCapabilities getServerCapabilities() { + return serverCapabilities; + } + + public void setInjectedMessageController(InjectedMessageController controller) { + injectedController = controller; + } + public abstract void connect(); public abstract EnumEaglerConnectionState getConnectStatus(); @@ -109,5 +129,7 @@ public abstract class EaglercraftNetworkManager { } } } - + + public abstract void injectRawFrame(byte[] data); + } \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/GuiHandshakeApprove.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/GuiHandshakeApprove.java index ede564ec..a45e2300 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/GuiHandshakeApprove.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/GuiHandshakeApprove.java @@ -104,4 +104,14 @@ public class GuiHandshakeApprove extends GuiScreen { } } + public static GuiScreen displayAuthProtocolConfirm(int protocol, GuiScreen no, GuiScreen yes) { + if(protocol == HandshakePacketTypes.AUTH_METHOD_PLAINTEXT) { + return new GuiHandshakeApprove("plaintext", no, yes); + }else if(protocol != HandshakePacketTypes.AUTH_METHOD_EAGLER_SHA256 && protocol != HandshakePacketTypes.AUTH_METHOD_AUTHME_SHA256) { + return new GuiHandshakeApprove("unsupportedAuth", no); + }else { + return null; + } + } + } \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/HandshakePacketTypes.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/HandshakePacketTypes.java index 02e61cc6..a7717f48 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/HandshakePacketTypes.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/HandshakePacketTypes.java @@ -29,12 +29,15 @@ public class HandshakePacketTypes { public static final int PROTOCOL_CLIENT_PROFILE_DATA = 0x07; public static final int PROTOCOL_CLIENT_FINISH_LOGIN = 0x08; public static final int PROTOCOL_SERVER_FINISH_LOGIN = 0x09; + public static final int PROTOCOL_SERVER_REDIRECT_TO = 0x0A; public static final int PROTOCOL_SERVER_ERROR = 0xFF; - public static final int STATE_OPENED = 0x00; - public static final int STATE_CLIENT_VERSION = 0x01; - public static final int STATE_CLIENT_LOGIN = 0x02; - public static final int STATE_CLIENT_COMPLETE = 0x03; + public static final int STATE_NEW = 0x00; + public static final int STATE_OPENED = 0x01; + public static final int STATE_CLIENT_VERSION = 0x02; + public static final int STATE_CLIENT_LOGIN = 0x03; + public static final int STATE_CLIENT_COMPLETE = 0x04; + public static final int STATE_FINISHED = 0x05; public static final int SERVER_ERROR_UNKNOWN_PACKET = 0x01; public static final int SERVER_ERROR_INVALID_PACKET = 0x02; diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/WebSocketNetworkManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/WebSocketNetworkManager.java index 5d58496e..2b4dea3d 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/WebSocketNetworkManager.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/WebSocketNetworkManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -71,6 +71,11 @@ public class WebSocketNetworkManager extends EaglercraftNetworkManager { ++debugPacketCounter; try { byte[] asByteArray = next.getByteArray(); + + if(injectedController != null && injectedController.handlePacket(asByteArray, 0)) { + continue; + } + ByteBuf nettyBuffer = Unpooled.buffer(asByteArray, asByteArray.length); nettyBuffer.writerIndex(asByteArray.length); PacketBuffer input = new PacketBuffer(nettyBuffer); @@ -150,4 +155,13 @@ public class WebSocketNetworkManager extends EaglercraftNetworkManager { } } + @Override + public void injectRawFrame(byte[] data) { + if(!isChannelOpen()) { + logger.error("Frame was injected on a closed connection"); + return; + } + webSocketClient.send(data); + } + } \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientMessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientMessageHandler.java new file mode 100644 index 00000000..f386432e --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientMessageHandler.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.client; + +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler; +import net.minecraft.client.network.NetHandlerPlayClient; + +public abstract class ClientMessageHandler implements GameMessageHandler { + + protected final NetHandlerPlayClient netHandler; + + public ClientMessageHandler(NetHandlerPlayClient netHandler) { + this.netHandler = netHandler; + } + + public static ClientMessageHandler createClientHandler(int version, NetHandlerPlayClient netHandler) { + switch(version) { + case 3: + return new ClientV3MessageHandler(netHandler); + case 4: + return new ClientV4MessageHandler(netHandler); + case 5: + return new ClientV5MessageHandler(netHandler); + default: + throw new UnsupportedOperationException(); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV3MessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV3MessageHandler.java index 231f82ee..07332f62 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV3MessageHandler.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV3MessageHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -20,20 +20,16 @@ import java.nio.charset.StandardCharsets; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; -import net.lax1dude.eaglercraft.v1_8.profile.SkinModel; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*; import net.lax1dude.eaglercraft.v1_8.update.UpdateService; import net.lax1dude.eaglercraft.v1_8.voice.VoiceClientController; import net.minecraft.client.Minecraft; import net.minecraft.client.network.NetHandlerPlayClient; -public class ClientV3MessageHandler implements GameMessageHandler { - - private final NetHandlerPlayClient netHandler; +public class ClientV3MessageHandler extends ClientMessageHandler { public ClientV3MessageHandler(NetHandlerPlayClient netHandler) { - this.netHandler = netHandler; + super(netHandler); } public void handleServer(SPacketEnableFNAWSkinsEAG packet) { @@ -44,35 +40,19 @@ public class ClientV3MessageHandler implements GameMessageHandler { } public void handleServer(SPacketOtherCapeCustomEAG packet) { - netHandler.getCapeCache().cacheCapeCustom(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), - packet.customCape); + netHandler.getTextureCache().handlePacket(packet); } public void handleServer(SPacketOtherCapePresetEAG packet) { - netHandler.getCapeCache().cacheCapePreset(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), - packet.presetCape); + netHandler.getTextureCache().handlePacket(packet); } public void handleServer(SPacketOtherSkinCustomV3EAG packet) { - EaglercraftUUID responseUUID = new EaglercraftUUID(packet.uuidMost, packet.uuidLeast); - SkinModel modelId; - if(packet.modelID == (byte)0xFF) { - modelId = this.netHandler.getSkinCache().getRequestedSkinType(responseUUID); - }else { - modelId = SkinModel.getModelFromId(packet.modelID & 0x7F); - if((packet.modelID & 0x80) != 0 && modelId.sanitize) { - modelId = SkinModel.STEVE; - } - } - if(modelId.highPoly != null) { - modelId = SkinModel.STEVE; - } - this.netHandler.getSkinCache().cacheSkinCustom(responseUUID, packet.customSkin, modelId); + netHandler.getTextureCache().handlePacket(packet); } public void handleServer(SPacketOtherSkinPresetEAG packet) { - this.netHandler.getSkinCache().cacheSkinPreset(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), - packet.presetSkin); + netHandler.getTextureCache().handlePacket(packet); } public void handleServer(SPacketUpdateCertEAG packet) { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV4MessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV4MessageHandler.java index 82d3c31f..b389f619 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV4MessageHandler.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV4MessageHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -16,81 +16,37 @@ package net.lax1dude.eaglercraft.v1_8.socket.protocol.client; -import java.nio.charset.StandardCharsets; - import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache; -import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState; import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore; import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile; -import net.lax1dude.eaglercraft.v1_8.profile.SkinModel; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler; +import net.lax1dude.eaglercraft.v1_8.skin_cache.ServerTextureCache; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.WrongPacketException; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*; import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache; -import net.lax1dude.eaglercraft.v1_8.update.UpdateService; import net.lax1dude.eaglercraft.v1_8.voice.VoiceClientController; import net.lax1dude.eaglercraft.v1_8.webview.ServerInfoCache; import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController; import net.minecraft.client.Minecraft; import net.minecraft.client.network.NetHandlerPlayClient; -public class ClientV4MessageHandler implements GameMessageHandler { - - private final NetHandlerPlayClient netHandler; +public class ClientV4MessageHandler extends ClientV3MessageHandler { public ClientV4MessageHandler(NetHandlerPlayClient netHandler) { - this.netHandler = netHandler; + super(netHandler); } - public void handleServer(SPacketEnableFNAWSkinsEAG packet) { - netHandler.currentFNAWSkinAllowedState = packet.enableSkins; - netHandler.currentFNAWSkinForcedState = packet.force; - Minecraft.getMinecraft().getRenderManager().setEnableFNAWSkins(netHandler.currentFNAWSkinForcedState - || (netHandler.currentFNAWSkinAllowedState && Minecraft.getMinecraft().gameSettings.enableFNAWSkins)); - } - - public void handleServer(SPacketOtherCapeCustomEAG packet) { - netHandler.getCapeCache().cacheCapeCustom(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), - packet.customCape); - } - - public void handleServer(SPacketOtherCapePresetEAG packet) { - netHandler.getCapeCache().cacheCapePreset(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), - packet.presetCape); + public void handleServer(SPacketOtherSkinCustomV3EAG packet) { + throw new WrongPacketException(); } public void handleServer(SPacketOtherSkinCustomV4EAG packet) { - EaglercraftUUID responseUUID = new EaglercraftUUID(packet.uuidMost, packet.uuidLeast); - SkinModel modelId; - if(packet.modelID == (byte)0xFF) { - modelId = this.netHandler.getSkinCache().getRequestedSkinType(responseUUID); - }else { - modelId = SkinModel.getModelFromId(packet.modelID & 0x7F); - if((packet.modelID & 0x80) != 0 && modelId.sanitize) { - modelId = SkinModel.STEVE; - } - } - if(modelId.highPoly != null) { - modelId = SkinModel.STEVE; - } - this.netHandler.getSkinCache().cacheSkinCustom(responseUUID, SkinPacketVersionCache.convertToV3Raw(packet.customSkin), modelId); + netHandler.getTextureCache().handlePacket(packet); } - public void handleServer(SPacketOtherSkinPresetEAG packet) { - this.netHandler.getSkinCache().cacheSkinPreset(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.presetSkin); - } - - public void handleServer(SPacketUpdateCertEAG packet) { - if (EagRuntime.getConfiguration().allowUpdateSvc()) { - UpdateService.addCertificateToSet(packet.updateCert); - } - } - - public void handleServer(SPacketVoiceSignalAllowedEAG packet) { - if (VoiceClientController.isClientSupported()) { - VoiceClientController.handleVoiceSignalPacketTypeAllowed(packet.allowed, packet.iceServers); - } + public void handleServer(SPacketVoiceSignalConnectV3EAG packet) { + throw new WrongPacketException(); } public void handleServer(SPacketVoiceSignalConnectV4EAG packet) { @@ -105,34 +61,6 @@ public class ClientV4MessageHandler implements GameMessageHandler { } } - public void handleServer(SPacketVoiceSignalDescEAG packet) { - if (VoiceClientController.isClientSupported()) { - VoiceClientController.handleVoiceSignalPacketTypeDescription( - new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), - new String(packet.desc, StandardCharsets.UTF_8)); - } - } - - public void handleServer(SPacketVoiceSignalDisconnectPeerEAG packet) { - if (VoiceClientController.isClientSupported()) { - VoiceClientController.handleVoiceSignalPacketTypeDisconnect(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); - } - } - - public void handleServer(SPacketVoiceSignalGlobalEAG packet) { - if (VoiceClientController.isClientSupported()) { - VoiceClientController.handleVoiceSignalPacketTypeGlobalNew(packet.users); - } - } - - public void handleServer(SPacketVoiceSignalICEEAG packet) { - if (VoiceClientController.isClientSupported()) { - VoiceClientController.handleVoiceSignalPacketTypeICECandidate( - new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), - new String(packet.ice, StandardCharsets.UTF_8)); - } - } - public void handleServer(SPacketForceClientSkinPresetV4EAG packet) { EaglerProfile.handleForceSkinPreset(packet.presetSkin); } @@ -166,14 +94,10 @@ public class ClientV4MessageHandler implements GameMessageHandler { public void handleServer(SPacketInvalidatePlayerCacheV4EAG packet) { if(packet.players != null && packet.players.size() > 0) { + ServerTextureCache textureCache = this.netHandler.getTextureCache(); for(SPacketInvalidatePlayerCacheV4EAG.InvalidateRequest req : packet.players) { - EaglercraftUUID uuid = new EaglercraftUUID(req.uuidMost, req.uuidLeast); - if(req.invalidateSkin) { - this.netHandler.getSkinCache().handleInvalidate(uuid); - } - if(req.invalidateCape) { - this.netHandler.getCapeCache().handleInvalidate(uuid); - } + textureCache.dropPlayer(new EaglercraftUUID(req.uuidMost, req.uuidLeast), + req.invalidateSkin, req.invalidateCape); } } } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV5MessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV5MessageHandler.java new file mode 100644 index 00000000..7d2f7b41 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV5MessageHandler.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.client; + +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.WrongPacketException; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*; +import net.lax1dude.eaglercraft.v1_8.webview.GuiScreenPhishingWarning; +import net.lax1dude.eaglercraft.v1_8.webview.GuiScreenRecieveServerInfo; +import net.lax1dude.eaglercraft.v1_8.webview.GuiScreenRequestDisplay; +import net.lax1dude.eaglercraft.v1_8.webview.GuiScreenServerInfo; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.network.NetHandlerPlayClient; + +public class ClientV5MessageHandler extends ClientV4MessageHandler { + + public ClientV5MessageHandler(NetHandlerPlayClient netHandler) { + super(netHandler); + } + + public void handleServer(SPacketOtherSkinPresetEAG packet) { + throw new WrongPacketException(); + } + + public void handleServer(SPacketOtherSkinCustomV4EAG packet) { + throw new WrongPacketException(); + } + + public void handleServer(SPacketOtherCapePresetEAG packet) { + throw new WrongPacketException(); + } + + public void handleServer(SPacketOtherCapeCustomEAG packet) { + throw new WrongPacketException(); + } + + public void handleServer(SPacketOtherSkinPresetV5EAG packet) { + netHandler.getTextureCache().handlePacket(packet); + } + + public void handleServer(SPacketOtherSkinCustomV5EAG packet) { + netHandler.getTextureCache().handlePacket(packet); + } + + public void handleServer(SPacketOtherCapePresetV5EAG packet) { + netHandler.getTextureCache().handlePacket(packet); + } + + public void handleServer(SPacketOtherCapeCustomV5EAG packet) { + netHandler.getTextureCache().handlePacket(packet); + } + + public void handleServer(SPacketOtherTexturesV5EAG packet) { + netHandler.getTextureCache().handlePacket(packet); + } + + public void handleServer(SPacketClientStateFlagV5EAG packet) { + StateFlags.setFlag(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.state); + } + + public void handleServer(SPacketDisplayWebViewURLV5EAG packet) { + if (netHandler.allowedDisplayWebview && !netHandler.allowedDisplayWebviewYes) { + return; + } + Minecraft mc = Minecraft.getMinecraft(); + GuiScreen screen = GuiScreenServerInfo.createForDisplayRequest(mc.currentScreen, packet.flags, + packet.embedTitle, packet.embedURL); + if (!mc.gameSettings.hasHiddenPhishWarning && !GuiScreenPhishingWarning.hasShownMessage) { + screen = new GuiScreenPhishingWarning(screen); + } + if (!netHandler.allowedDisplayWebview) { + mc.displayGuiScreen(new GuiScreenRequestDisplay(screen, mc.currentScreen, netHandler)); + } else { + mc.displayGuiScreen(screen); + } + } + + public void handleServer(SPacketDisplayWebViewBlobV5EAG packet) { + if (netHandler.allowedDisplayWebview && !netHandler.allowedDisplayWebviewYes) { + return; + } + Minecraft mc = Minecraft.getMinecraft(); + GuiScreen screen = new GuiScreenRecieveServerInfo(mc.currentScreen, packet.embedHash, + (parent, blob, permissionsOriginUUID) -> { + return GuiScreenServerInfo.createForDisplayRequest(parent, packet.flags, packet.embedTitle, blob, + permissionsOriginUUID); + }); + if (!mc.gameSettings.hasHiddenPhishWarning && !GuiScreenPhishingWarning.hasShownMessage) { + screen = new GuiScreenPhishingWarning(screen); + } + if (!netHandler.allowedDisplayWebview) { + mc.displayGuiScreen(new GuiScreenRequestDisplay(screen, mc.currentScreen, netHandler)); + } else { + mc.displayGuiScreen(screen); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java deleted file mode 100644 index 8340bed3..00000000 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2024 lax1dude. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -package net.lax1dude.eaglercraft.v1_8.socket.protocol.client; - -import java.io.IOException; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import net.lax1dude.eaglercraft.v1_8.EagRuntime; -import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; -import net.lax1dude.eaglercraft.v1_8.log4j.Logger; -import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePacketOutputBuffer; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; -import net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol.ServerV3MessageHandler; -import net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol.ServerV4MessageHandler; -import net.minecraft.client.network.NetHandlerPlayClient; -import net.minecraft.network.NetHandlerPlayServer; -import net.minecraft.network.PacketBuffer; - -public class GameProtocolMessageController { - - private static final Logger logger = LogManager.getLogger("GameProtocolMessageController"); - - public final GamePluginMessageProtocol protocol; - public final int sendDirection; - public final int receiveDirection; - private final PacketBufferInputWrapper inputStream = new PacketBufferInputWrapper(null); - private final PacketBufferOutputWrapper outputStream = new PacketBufferOutputWrapper(null); - private final GameMessageHandler handler; - private final IPluginMessageSendFunction sendFunction; - private final List sendQueueV4; - private final boolean noDelay; - - public GameProtocolMessageController(GamePluginMessageProtocol protocol, int sendDirection, GameMessageHandler handler, - IPluginMessageSendFunction sendCallback) { - this.protocol = protocol; - this.sendDirection = sendDirection; - this.receiveDirection = GamePluginMessageConstants.oppositeDirection(sendDirection); - this.handler = handler; - this.sendFunction = sendCallback; - this.noDelay = protocol.ver < 4 || EagRuntime.getConfiguration().isEaglerNoDelay(); - this.sendQueueV4 = !noDelay ? new LinkedList<>() : null; - } - - public boolean handlePacket(String channel, PacketBuffer data) throws IOException { - GameMessagePacket pkt; - if(protocol.ver >= 4 && data.readableBytes() > 0 && data.getByte(data.readerIndex()) == (byte) 0xFF - && channel.equals(GamePluginMessageConstants.V4_CHANNEL)) { - data.readByte(); - inputStream.buffer = data; - int count = inputStream.readVarInt(); - for(int i = 0, j, k; i < count; ++i) { - j = data.readVarIntFromBuffer(); - k = data.readerIndex() + j; - if(j > data.readableBytes()) { - throw new IOException("Packet fragment is too long: " + j + " > " + data.readableBytes()); - } - pkt = protocol.readPacket(channel, receiveDirection, inputStream); - if(pkt != null) { - try { - pkt.handlePacket(handler); - }catch(Throwable t) { - logger.error("Failed to handle packet {} in direction {} using handler {}!", pkt.getClass().getSimpleName(), - GamePluginMessageConstants.getDirectionString(receiveDirection), handler); - logger.error(t); - } - }else { - logger.warn("Could not read packet fragment {} of {}, unknown packet", count, i); - } - if(data.readerIndex() != k) { - logger.warn("Packet fragment {} was the wrong length: {} != {}", - (pkt != null ? pkt.getClass().getSimpleName() : "unknown"), j + data.readerIndex() - k, j); - data.readerIndex(k); - } - } - if(data.readableBytes() > 0) { - logger.warn("Leftover data after reading multi-packet! ({} bytes)", data.readableBytes()); - } - inputStream.buffer = null; - return true; - } - inputStream.buffer = data; - pkt = protocol.readPacket(channel, receiveDirection, inputStream); - if(pkt != null && inputStream.available() > 0) { - logger.warn("Leftover data after reading packet {}! ({} bytes)", pkt.getClass().getSimpleName(), inputStream.available()); - } - inputStream.buffer = null; - if(pkt != null) { - try { - pkt.handlePacket(handler); - }catch(Throwable t) { - logger.error("Failed to handle packet {} in direction {} using handler {}!", pkt.getClass().getSimpleName(), - GamePluginMessageConstants.getDirectionString(receiveDirection), handler); - logger.error(t); - } - return true; - }else { - return false; - } - } - - public void sendPacket(GameMessagePacket packet) throws IOException { - int len = packet.length() + 1; - PacketBuffer buf = new PacketBuffer(len != 0 ? Unpooled.buffer(len) : Unpooled.buffer(64)); - outputStream.buffer = buf; - String chan = protocol.writePacket(sendDirection, outputStream, packet); - outputStream.buffer = null; - int j = buf.writerIndex(); - if(len != 0 && j != len && j + 1 != len) { - logger.warn("Packet {} was expected to be {} bytes but was serialized to {} bytes!", - packet.getClass().getSimpleName(), len, j); - } - if(sendQueueV4 != null && chan.equals(GamePluginMessageConstants.V4_CHANNEL)) { - sendQueueV4.add(buf); - }else { - sendFunction.sendPluginMessage(chan, buf); - } - } - - public void flush() { - if(sendQueueV4 != null) { - int queueLen = sendQueueV4.size(); - PacketBuffer pkt; - if(queueLen == 0) { - return; - }else if(queueLen == 1) { - pkt = sendQueueV4.remove(0); - sendFunction.sendPluginMessage(GamePluginMessageConstants.V4_CHANNEL, pkt); - }else { - int i, j, sendCount, totalLen, lastLen; - PacketBuffer sendBuffer; - while(sendQueueV4.size() > 0) { - sendCount = 0; - totalLen = 0; - Iterator itr = sendQueueV4.iterator(); - do { - i = itr.next().readableBytes(); - lastLen = GamePacketOutputBuffer.getVarIntSize(i) + i; - totalLen += lastLen; - ++sendCount; - }while(totalLen < 32760 && itr.hasNext()); - if(totalLen >= 32760) { - --sendCount; - totalLen -= lastLen; - } - if(sendCount <= 1) { - pkt = sendQueueV4.remove(0); - sendFunction.sendPluginMessage(GamePluginMessageConstants.V4_CHANNEL, pkt); - continue; - } - sendBuffer = new PacketBuffer(Unpooled.buffer(1 + totalLen + GamePacketOutputBuffer.getVarIntSize(sendCount))); - sendBuffer.writeByte(0xFF); - sendBuffer.writeVarIntToBuffer(sendCount); - for(j = 0; j < sendCount; ++j) { - pkt = sendQueueV4.remove(0); - sendBuffer.writeVarIntToBuffer(pkt.readableBytes()); - sendBuffer.writeBytes(pkt); - } - sendFunction.sendPluginMessage(GamePluginMessageConstants.V4_CHANNEL, sendBuffer); - } - } - } - } - - public static GameMessageHandler createClientHandler(int protocolVersion, NetHandlerPlayClient netHandler) { - switch(protocolVersion) { - case 2: - case 3: - return new ClientV3MessageHandler(netHandler); - case 4: - return new ClientV4MessageHandler(netHandler); - default: - throw new IllegalArgumentException("Unknown protocol verison: " + protocolVersion); - } - } - - public static GameMessageHandler createServerHandler(int protocolVersion, NetHandlerPlayServer netHandler) { - switch(protocolVersion) { - case 2: - case 3: - return new ServerV3MessageHandler(netHandler); - case 4: - return new ServerV4MessageHandler(netHandler); - default: - throw new IllegalArgumentException("Unknown protocol verison: " + protocolVersion); - } - } -} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/StateFlags.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/StateFlags.java new file mode 100644 index 00000000..80a7548f --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/StateFlags.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.client; + +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; + +public class StateFlags { + + public static final EaglercraftUUID EAGLER_PLAYER_FLAG_PRESENT = new EaglercraftUUID(0x55F63601694140D9L, + 0xB77BCE7B99A62E52L); + + public static final EaglercraftUUID LEGACY_EAGLER_PLAYER_FLAG_PRESENT = new EaglercraftUUID(0xEEEEA64771094C4EL, + 0x86E55B81D17E67EBL); + + public static final EaglercraftUUID DISABLE_SKIN_URL_LOOKUP = new EaglercraftUUID(0xC41D641BE2DA4094L, + 0xB1B2DFF2E9D08180L); + + public static boolean eaglerPlayerFlag = false; + + public static boolean eaglerPlayerFlagSupervisor = false; + + public static boolean disableSkinURLLookup = false; + + public static void setFlag(EaglercraftUUID flag, int value) { + if (flag.equals(EAGLER_PLAYER_FLAG_PRESENT)) { + eaglerPlayerFlag = (value & 1) != 0; + eaglerPlayerFlagSupervisor = (value & 2) != 0; + } else if (flag.equals(DISABLE_SKIN_URL_LOOKUP)) { + disableSkinURLLookup = value != 0; + } + } + + public static void reset() { + eaglerPlayerFlag = false; + eaglerPlayerFlagSupervisor = false; + disableSkinURLLookup = false; + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/AuthTypes.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/AuthTypes.java new file mode 100644 index 00000000..f696dac2 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/AuthTypes.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake; + +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.crypto.SHA256Digest; +import net.lax1dude.eaglercraft.v1_8.socket.HandshakePacketTypes; + +public class AuthTypes { + + public static byte[] applyEaglerSHA256(String password, byte[] salt) { + SHA256Digest digest = new SHA256Digest(); + + int passLen = password.length(); + + digest.update((byte)((passLen >>> 8) & 0xFF)); + digest.update((byte)(passLen & 0xFF)); + + for (int i = 0; i < passLen; ++i) { + char codePoint = password.charAt(i); + digest.update((byte)((codePoint >>> 8) & 0xFF)); + digest.update((byte)(codePoint & 0xFF)); + } + + digest.update(HandshakePacketTypes.EAGLER_SHA256_SALT_SAVE, 0, 32); + + byte[] hashed = new byte[32]; + digest.doFinal(hashed, 0); + + digest.reset(); + + digest.update(hashed, 0, 32); + digest.update(salt, 0, 32); + digest.update(HandshakePacketTypes.EAGLER_SHA256_SALT_BASE, 0, 32); + + digest.doFinal(hashed, 0); + + digest.reset(); + + digest.update(hashed, 0, 32); + digest.update(salt, 32, 32); + digest.update(HandshakePacketTypes.EAGLER_SHA256_SALT_BASE, 0, 32); + + digest.doFinal(hashed, 0); + + return hashed; + } + + public static byte[] applyAuthMeSHA256(String password, byte[] salt) { + SHA256Digest digest = new SHA256Digest(); + + byte[] passwd = password.getBytes(StandardCharsets.UTF_8); + digest.update(passwd, 0, passwd.length); + + byte[] hashed = new byte[32]; + digest.doFinal(hashed, 0); + + byte[] toHexAndSalt = new byte[64]; + for (int i = 0; i < 32; ++i) { + toHexAndSalt[i << 1] = HEX[(hashed[i] >> 4) & 0xF]; + toHexAndSalt[(i << 1) + 1] = HEX[hashed[i] & 0xF]; + } + + digest.reset(); + digest.update(toHexAndSalt, 0, 64); + digest.update(salt, 0, salt.length); + + digest.doFinal(hashed, 0); + + for (int i = 0; i < 32; ++i) { + toHexAndSalt[i << 1] = HEX[(hashed[i] >> 4) & 0xF]; + toHexAndSalt[(i << 1) + 1] = HEX[hashed[i] & 0xF]; + } + + return toHexAndSalt; + } + + private static final byte[] HEX = new byte[] { + (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', + (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f' + }; + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/ClientCapabilities.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/ClientCapabilities.java new file mode 100644 index 00000000..345815b0 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/ClientCapabilities.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake; + +import java.util.ArrayList; +import java.util.List; + +import com.carrotsearch.hppc.IntArrayList; + +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.update.UpdateService; +import net.lax1dude.eaglercraft.v1_8.voice.VoiceClientController; +import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController; + +public class ClientCapabilities { + + static ClientCapabilities createCapabilities(boolean cookie) { + ClientCapabilities caps = new ClientCapabilities(); + + caps.addStandard(StandardCaps.REDIRECT, 0); + caps.addStandard(StandardCaps.NOTIFICATION, 0); + caps.addStandard(StandardCaps.PAUSE_MENU, 0); + + if (VoiceClientController.isClientSupported()) { + caps.addStandard(StandardCaps.VOICE, 0); + } + + if (UpdateService.supported()) { + caps.addStandard(StandardCaps.UPDATE, 0); + } + + if (WebViewOverlayController.supported() || WebViewOverlayController.fallbackSupported()) { + caps.addStandard(StandardCaps.WEBVIEW, 0); + } + + if (cookie) { + caps.addStandard(StandardCaps.COOKIE, 0); + } + + return caps; + } + + static class ExtCapability { + final EaglercraftUUID uuid; + final int vers; + ExtCapability(EaglercraftUUID uuid, int vers) { + this.uuid = uuid; + this.vers = vers; + } + } + + private int standardCaps = 0; + private IntArrayList standardCapsVers = new IntArrayList(); + private List extendedCaps = new ArrayList<>(); + + int getStandardCaps() { + return standardCaps; + } + + int[] getStandardCapsVers() { + return standardCapsVers.toArray(); + } + + ExtCapability[] getExtendedCaps() { + return extendedCaps.toArray(new ExtCapability[extendedCaps.size()]); + } + + private void addStandard(int type, int... versions) { + int bit = (1 << type); + standardCapsVers.insert(Integer.bitCount(standardCaps & (bit - 1)), bits(versions)); + standardCaps |= bit; + } + + private void addExtended(EaglercraftUUID type, int... versions) { + extendedCaps.add(new ExtCapability(type, bits(versions))); + } + + private int bits(int... versions) { + int bits = 0; + for(int i = 0; i < versions.length; ++i) { + bits |= (1 << versions[i]); + } + return bits; + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerHandler.java new file mode 100644 index 00000000..c66f831b --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerHandler.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.ArrayUtils; +import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream; +import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion; +import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient; +import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame; +import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; +import net.lax1dude.eaglercraft.v1_8.log4j.Logger; +import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; +import net.lax1dude.eaglercraft.v1_8.profile.GuiAuthenticationScreen; +import net.lax1dude.eaglercraft.v1_8.socket.HandshakePacketTypes; +import net.lax1dude.eaglercraft.v1_8.socket.RateLimitTracker; +import net.lax1dude.eaglercraft.v1_8.socket.WebSocketNetworkManager; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiDisconnected; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.multiplayer.GuiConnecting; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.network.EnumConnectionState; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.IChatComponent; + +public class HandshakerHandler { + + static final Logger logger = LogManager.getLogger("HandshakerHandler"); + + protected final Minecraft mc; + protected final IWebSocketClient websocket; + protected final GuiConnecting parent; + protected final GuiScreen ret; + protected final String username; + protected final String password; + protected final boolean allowPlaintext; + protected final boolean enableCookies; + protected final byte[] cookieData; + protected HandshakerInstance handshaker; + protected boolean nicknameSelection = true; + protected int baseState = NEW; + protected WebSocketNetworkManager networkManager; + + protected static final int NEW = 0, SENT_HANDSHAKE = 1, PROCESSING = 2, FINISHED = 3; + + public HandshakerHandler(GuiConnecting parent, IWebSocketClient websocket, String username, String password, + boolean allowPlaintext, boolean enableCookies, byte[] cookieData) { + this.mc = GuiConnecting.getMC(parent); + this.websocket = websocket; + this.parent = parent; + this.ret = GuiConnecting.getPrevScreen(parent); + this.username = username; + this.password = password; + this.allowPlaintext = allowPlaintext; + this.enableCookies = enableCookies; + this.cookieData = cookieData; + } + + private static final int protocolV3 = 3; + private static final int protocolV4 = 4; + private static final int protocolV5 = 5; + + public static byte[] getSPHandshakeProtocolData() { + try { + EaglerOutputStream bao = new EaglerOutputStream(); + DataOutputStream d = new DataOutputStream(bao); + d.writeShort(3); // supported eagler protocols count + d.writeShort(protocolV3); // client supports v3 + d.writeShort(protocolV4); // client supports v4 + d.writeShort(protocolV5); // client supports v5 + return bao.toByteArray(); + }catch(IOException ex) { + throw new RuntimeException(ex); + } + } + + public void tick() { + if(baseState == NEW) { + if(websocket.isClosed()) { + handleError("Connection Closed", null); + return; + } + baseState = SENT_HANDSHAKE; + beginHandshake(); + }else if(baseState == SENT_HANDSHAKE) { + IWebSocketFrame frame = websocket.getNextBinaryFrame(); + if(frame != null) { + byte[] data = frame.getByteArray(); + handleServerHandshake(new PacketBuffer(Unpooled.buffer(data, data.length).writerIndex(data.length))); + } + }else if(baseState == PROCESSING) { + handshaker.tick(); + }else if(baseState == FINISHED) { + if(networkManager != null) { + try { + networkManager.processReceivedPackets(); + } catch (IOException e) { + } + } + } + } + + protected void beginHandshake() { + PacketBuffer buffer = new PacketBuffer(Unpooled.buffer()); + + buffer.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_VERSION); + + buffer.writeByte(2); // legacy protocol version + + buffer.writeBytes(getSPHandshakeProtocolData()); // write supported eagler protocol versions + + buffer.writeShort(1); // supported game protocols count + buffer.writeShort(47); // client supports 1.8 protocol + + String clientBrand = EaglercraftVersion.projectForkName; + buffer.writeByte(clientBrand.length()); + writeASCII(buffer, clientBrand); + + String clientVers = EaglercraftVersion.projectOriginVersion; + buffer.writeByte(clientVers.length()); + writeASCII(buffer, clientVers); + + buffer.writeBoolean(password != null); + + buffer.writeByte(username.length()); + writeASCII(buffer, username); + + websocket.send(buffer.toBytes()); + } + + protected static void writeASCII(PacketBuffer buffer, String str) { + for(int i = 0, l = str.length(); i < l; ++i) { + buffer.writeByte(str.charAt(i)); + } + } + + protected void handleServerHandshake(PacketBuffer packet) { + try { + int pktId = packet.readUnsignedByte(); + switch(pktId) { + case HandshakePacketTypes.PROTOCOL_SERVER_VERSION: + handleServerVersion(packet); + break; + case HandshakePacketTypes.PROTOCOL_VERSION_MISMATCH: + handleVersionMismatch(packet); + break; + case HandshakePacketTypes.PROTOCOL_SERVER_ERROR: + handleServerError(packet, false); + break; + default: + handleError("connect.failed", new ChatComponentText("Unknown packet type " + pktId + " received")); + break; + } + }catch(Exception ex) { + handleError("connect.failed", new ChatComponentText("Invalid packet received")); + logger.error("Invalid packet received"); + logger.error(ex); + } + } + + protected void handleServerVersion(PacketBuffer packet) { + int protocolVersion = packet.readUnsignedShort(); + + if(protocolVersion != protocolV3 && protocolVersion != protocolV4 && protocolVersion != protocolV5) { + logger.info("Incompatible server version: {}", protocolVersion); + handleError("connect.failed", new ChatComponentText(protocolVersion < protocolV3 ? "Outdated Server" : "Outdated Client")); + return; + } + + int gameVers = packet.readUnsignedShort(); + if(gameVers != 47) { + logger.info("Incompatible minecraft protocol version: {}", gameVers); + handleError("connect.failed", new ChatComponentText("This server does not support 1.8!")); + return; + } + + logger.info("Server protocol: {}", protocolVersion); + + int msgLen = packet.readUnsignedByte(); + byte[] dat = new byte[msgLen]; + packet.readBytes(dat); + String pluginBrand = ArrayUtils.asciiString(dat); + + msgLen = packet.readUnsignedByte(); + dat = new byte[msgLen]; + packet.readBytes(dat); + String pluginVersion = ArrayUtils.asciiString(dat); + + logger.info("Server version: {}", pluginVersion); + logger.info("Server brand: {}", pluginBrand); + + int authType = packet.readUnsignedByte(); + int saltLength = (int)packet.readUnsignedShort() & 0xFFFF; + + byte[] salt = new byte[saltLength]; + packet.readBytes(salt); + + if(protocolVersion >= protocolV5) { + nicknameSelection = packet.readBoolean(); + } + + baseState = PROCESSING; + switch(protocolVersion) { + case protocolV3: + handshaker = new HandshakerV3(this); + break; + case protocolV4: + handshaker = new HandshakerV4(this); + break; + case protocolV5: + handshaker = new HandshakerV5(this); + break; + } + + handshaker.begin(pluginBrand, pluginVersion, authType, salt); + } + + protected void handleVersionMismatch(PacketBuffer packet) { + StringBuilder protocols = new StringBuilder(); + int c = packet.readUnsignedShort(); + for(int i = 0; i < c; ++i) { + if(i > 0) { + protocols.append(", "); + } + protocols.append("v").append(packet.readUnsignedShort()); + } + + StringBuilder games = new StringBuilder(); + c = packet.readUnsignedShort(); + for(int i = 0; i < c; ++i) { + if(i > 0) { + games.append(", "); + } + games.append("mc").append(packet.readUnsignedShort()); + } + + logger.info("Incompatible client: v3/v4/v5 & mc47"); + logger.info("Server supports: {}", protocols); + logger.info("Server supports: {}", games); + + int msgLen = packet.readUnsignedByte(); + byte[] dat = new byte[msgLen]; + packet.readBytes(dat); + String msg = new String(dat, StandardCharsets.UTF_8); + + handleError("connect.failed", new ChatComponentText(msg)); + } + + protected void handleServerError(PacketBuffer packet, boolean v3) { + int errCode = packet.readUnsignedByte(); + int msgLen; + if(v3) { + msgLen = packet.readUnsignedShort(); + if(msgLen == 0 && packet.readableBytes() == 65536) { + // workaround for bug in EaglerXBungee 1.2.7 and below + msgLen = 65536; + } + }else { + msgLen = packet.readUnsignedByte(); + if(msgLen == 0 && packet.readableBytes() == 256) { + // workaround for bug in EaglerXBungee 1.2.7 and below + msgLen = 256; + } + } + byte[] dat = new byte[msgLen]; + packet.readBytes(dat); + String msg = new String(dat, StandardCharsets.UTF_8); + if(errCode == HandshakePacketTypes.SERVER_ERROR_RATELIMIT_BLOCKED) { + handleRatelimit(false, new ChatComponentText(msg)); + }else if(errCode == HandshakePacketTypes.SERVER_ERROR_RATELIMIT_LOCKED) { + handleRatelimit(true, new ChatComponentText(msg)); + }else if(errCode == HandshakePacketTypes.SERVER_ERROR_AUTHENTICATION_REQUIRED) { + handleAuthRequired(msg); + }else if(errCode == HandshakePacketTypes.SERVER_ERROR_CUSTOM_MESSAGE) { + handleError("connect.failed", v3 ? IChatComponent.Serializer.jsonToComponent(msg) : new ChatComponentText(msg)); + }else { + handleError("connect.failed", new ChatComponentText("Server Error Code " + errCode + "\n" + msg)); + } + } + + protected void handleSuccess() { + if(baseState != FINISHED) { + baseState = FINISHED; + websocket.setEnableStringFrames(false); + websocket.clearStringFrames(); + networkManager = new WebSocketNetworkManager(websocket); + networkManager.setPluginInfo(handshaker.pluginBrand, handshaker.pluginVersion, new ServerCapabilities( + handshaker.serverStandardCaps, handshaker.serverStandardCapVers, handshaker.extendedCaps)); + mc.bungeeOutdatedMsgTimer = 80; + mc.clearTitles(); + mc.getSession().update(handshaker.username, handshaker.uuid); + networkManager.setConnectionState(EnumConnectionState.PLAY); + new NetHandlerPlayClient(this.mc, ret, networkManager, this.mc.getSession().getProfile(), + GamePluginMessageProtocol.getByVersion(handshaker.getVersion())); + } + } + + protected void handleServerRedirectTo(String address) { + mc.handleReconnectPacket(address); + websocket.close(); + if(baseState != FINISHED) { + baseState = FINISHED; + mc.displayGuiScreen(ret); + } + } + + protected void handleRatelimit(boolean locked, IChatComponent detail) { + if(locked) { + RateLimitTracker.registerLockOut(websocket.getCurrentURI()); + }else { + RateLimitTracker.registerBlock(websocket.getCurrentURI()); + } + websocket.close(); + if(baseState != FINISHED) { + baseState = FINISHED; + mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(ret)); + } + } + + protected void handleError(String message, IChatComponent detail) { + websocket.close(); + if(baseState != FINISHED) { + baseState = FINISHED; + mc.displayGuiScreen(new GuiDisconnected(ret, message, detail != null ? detail : new ChatComponentText(""))); + } + } + + protected void handleAuthRequired(String message) { + websocket.close(); + if(baseState != FINISHED) { + baseState = FINISHED; + mc.displayGuiScreen(new GuiAuthenticationScreen(parent, ret, message)); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerInstance.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerInstance.java new file mode 100644 index 00000000..08366f24 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerInstance.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import com.carrotsearch.hppc.ObjectByteMap; + +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion; +import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame; +import net.lax1dude.eaglercraft.v1_8.netty.ByteBuf; +import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; +import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile; +import net.lax1dude.eaglercraft.v1_8.socket.HandshakePacketTypes; +import net.lax1dude.eaglercraft.v1_8.update.UpdateService; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.IChatComponent; + +public abstract class HandshakerInstance { + + protected final HandshakerHandler handler; + protected String pluginBrand; + protected String pluginVersion; + protected String username; + protected EaglercraftUUID uuid; + protected int state = HandshakePacketTypes.STATE_NEW; + protected int serverStandardCaps; + protected byte[] serverStandardCapVers; + protected ObjectByteMap extendedCaps; + + public HandshakerInstance(HandshakerHandler handler) { + this.handler = handler; + } + + protected void begin(String pluginBrand, String pluginVersion, int authType, byte[] salt) { + this.pluginBrand = pluginBrand; + this.pluginVersion = pluginVersion; + byte[] password = null; + if (handler.password != null) { + switch(authType) { + case HandshakePacketTypes.AUTH_METHOD_NONE: + break; + case HandshakePacketTypes.AUTH_METHOD_EAGLER_SHA256: + password = AuthTypes.applyEaglerSHA256(handler.password, salt); + break; + case HandshakePacketTypes.AUTH_METHOD_AUTHME_SHA256: + password = AuthTypes.applyAuthMeSHA256(handler.password, salt); + break; + case HandshakePacketTypes.AUTH_METHOD_PLAINTEXT: + if(!handler.allowPlaintext) { + handleError("disconnect.loginFailed", new ChatComponentText("Server attempted insecure plaintext authentication without user consent!")); + return; + } + password = handler.password.getBytes(StandardCharsets.UTF_8); + if(password.length > 255) { + handleError("disconnect.loginFailed", new ChatComponentText("Password is too long!")); + return; + } + break; + default: + handleError("disconnect.loginFailed", new ChatComponentText("Unknown auth method #" + authType + " requested")); + return; + } + } + + sendClientRequestLogin(handler.username, "default", password, handler.enableCookies, handler.cookieData); + + state = HandshakePacketTypes.STATE_CLIENT_LOGIN; + } + + protected abstract int getVersion(); + + protected abstract void sendClientRequestLogin(String username, String requestedServer, byte[] password, + boolean enableCookies, byte[] cookie); + + protected void tick() { + IWebSocketFrame frame; + while (state != HandshakePacketTypes.STATE_FINISHED + && (frame = handler.websocket.getNextBinaryFrame()) != null) { + handleInboundPacket(frame.getByteArray()); + } + if(handler.websocket.isClosed()) { + handleError("Connection Closed", (IChatComponent) null); + } + } + + protected void handleInboundPacket(byte[] data) { + try { + PacketBuffer buffer = new PacketBuffer(Unpooled.buffer(data, data.length).writerIndex(data.length)); + int pktId = buffer.readUnsignedByte(); + switch(pktId) { + case HandshakePacketTypes.PROTOCOL_SERVER_ALLOW_LOGIN: + handleInboundServerAllowLogin(buffer); + break; + case HandshakePacketTypes.PROTOCOL_SERVER_DENY_LOGIN: + handleInboundServerDenyLogin(buffer); + break; + case HandshakePacketTypes.PROTOCOL_SERVER_FINISH_LOGIN: + handleServerFinishLogin(); + break; + case HandshakePacketTypes.PROTOCOL_SERVER_REDIRECT_TO: + handleInboundServerRedirectTo(buffer); + break; + case HandshakePacketTypes.PROTOCOL_SERVER_ERROR: + handleInboundServerError(buffer); + break; + default: + handleError("connect.failed", "Unknown packet type " + pktId + " received"); + break; + } + }catch(Exception ex) { + handler.handleError("connect.failed", new ChatComponentText("Invalid packet received")); + HandshakerHandler.logger.error("Invalid packet received"); + HandshakerHandler.logger.error(ex); + } + } + + protected void handleError(String message, String detail) { + state = HandshakePacketTypes.STATE_FINISHED; + handler.handleError(message, IChatComponent.Serializer.jsonToComponent(detail)); + } + + protected void handleError(String message, IChatComponent detail) { + state = HandshakePacketTypes.STATE_FINISHED; + handler.handleError(message, detail); + } + + protected abstract void handleInboundServerAllowLogin(PacketBuffer buffer); + + protected abstract void handleInboundServerDenyLogin(PacketBuffer buffer); + + protected void handleServerAllowLogin(String username, EaglercraftUUID uuid, int serverStandardCaps, + byte[] serverStandardCapVers, ObjectByteMap extendedCaps) { + if(state != HandshakePacketTypes.STATE_CLIENT_LOGIN) { + handleError("connect.failed", "Unexpected allow login packet in state " + state); + return; + } + + this.username = username; + this.uuid = uuid; + this.serverStandardCaps = serverStandardCaps; + this.serverStandardCapVers = serverStandardCapVers; + this.extendedCaps = extendedCaps; + + Map profileDataToSend = new HashMap<>(); + + if(getVersion() >= 4) { + byte[] arr = new byte[16]; + ByteBuf buf = Unpooled.buffer(arr, 16); + buf.writeLong(EaglercraftVersion.clientBrandUUID.msb); + buf.writeLong(EaglercraftVersion.clientBrandUUID.lsb); + profileDataToSend.put("brand_uuid_v1", arr); + } + + byte[] packetSkin = EaglerProfile.getSkinPacket(getVersion()); + if(packetSkin.length > 0xFFFF) { + handleError("connect.failed", new ChatComponentText("Skin packet is too long: " + packetSkin.length)); + return; + } + profileDataToSend.put(getVersion() >= 4 ? "skin_v2" : "skin_v1", packetSkin); + + byte[] packetCape = EaglerProfile.getCapePacket(); + if(packetCape.length > 0xFFFF) { + handleError("connect.failed", new ChatComponentText("Cape packet is too long: " + packetCape.length)); + return; + } + profileDataToSend.put("cape_v1", packetCape); + + byte[] packetSignatureData = UpdateService.getClientSignatureData(); + if(packetSignatureData != null) { + profileDataToSend.put("update_cert_v1", packetSignatureData); + } + + sendClientProfileData(profileDataToSend); + + sendFinishLogin(); + + state = HandshakePacketTypes.STATE_CLIENT_COMPLETE; + } + + protected abstract void sendClientProfileData(Map profileDataToSend); + + protected abstract void sendFinishLogin(); + + protected void handleServerFinishLogin() { + if(state != HandshakePacketTypes.STATE_CLIENT_COMPLETE) { + handleError("connect.failed", "Unexpected finish login packet in state " + state); + return; + } + + state = HandshakePacketTypes.STATE_FINISHED; + + handler.handleSuccess(); + } + + protected abstract void handleInboundServerRedirectTo(PacketBuffer buffer); + + protected void handleServerRedirectTo(String address) { + state = HandshakePacketTypes.STATE_FINISHED; + + handler.handleServerRedirectTo(address); + } + + protected abstract void handleInboundServerError(PacketBuffer buffer); + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerV3.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerV3.java new file mode 100644 index 00000000..66e8a48b --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerV3.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake; + +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import net.lax1dude.eaglercraft.v1_8.ArrayUtils; +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; +import net.lax1dude.eaglercraft.v1_8.socket.HandshakePacketTypes; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.IChatComponent; + +public class HandshakerV3 extends HandshakerInstance { + + public HandshakerV3(HandshakerHandler handler) { + super(handler); + } + + @Override + protected int getVersion() { + return 3; + } + + @Override + protected void sendClientRequestLogin(String username, String requestedServer, byte[] password, + boolean enableCookies, byte[] cookie) { + PacketBuffer buffer = new PacketBuffer(Unpooled.buffer()); + buffer.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_REQUEST_LOGIN); + buffer.writeByte(username.length()); + HandshakerHandler.writeASCII(buffer, username); + buffer.writeByte(requestedServer.length()); + HandshakerHandler.writeASCII(buffer, requestedServer); + if(password != null) { + buffer.writeByte(password.length); + buffer.writeBytes(password); + }else { + buffer.writeByte(0); + } + handler.websocket.send(buffer.toBytes()); + } + + @Override + protected void handleInboundServerAllowLogin(PacketBuffer buffer) { + byte[] username = new byte[buffer.readUnsignedByte()]; + buffer.readBytes(username); + EaglercraftUUID uuid = new EaglercraftUUID(buffer.readLong(), buffer.readLong()); + handleServerAllowLogin(ArrayUtils.asciiString(username), uuid, ServerCapabilities.VIRTUAL_V3_SERVER_CAPS, + ServerCapabilities.VIRTUAL_V3_SERVER_CAPS_VERS, null); + } + + @Override + protected void handleInboundServerDenyLogin(PacketBuffer buffer) { + byte[] dat = new byte[buffer.readUnsignedShort()]; + buffer.readBytes(dat); + handleError("disconnect.loginFailed", + IChatComponent.Serializer.jsonToComponent(new String(dat, StandardCharsets.UTF_8))); + } + + @Override + protected void sendClientProfileData(Map profileDataToSend) { + for(Map.Entry etr : profileDataToSend.entrySet()) { + PacketBuffer buffer = new PacketBuffer(Unpooled.buffer()); + buffer.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_PROFILE_DATA); + String profileDataType = etr.getKey(); + buffer.writeByte(profileDataType.length()); + HandshakerHandler.writeASCII(buffer, profileDataType); + byte[] data = etr.getValue(); + buffer.writeShort(data.length); + buffer.writeBytes(data); + handler.websocket.send(buffer.toBytes()); + } + } + + @Override + protected void sendFinishLogin() { + handler.websocket.send(new byte[] { (byte) HandshakePacketTypes.PROTOCOL_CLIENT_FINISH_LOGIN }); + } + + @Override + protected void handleInboundServerRedirectTo(PacketBuffer buffer) { + handleError("disconnect.loginFailed", "Unexpected login redirect packet"); + } + + @Override + protected void handleInboundServerError(PacketBuffer buffer) { + state = HandshakePacketTypes.STATE_FINISHED; + handler.handleServerError(buffer, true); + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerV4.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerV4.java new file mode 100644 index 00000000..2cfee650 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerV4.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import net.lax1dude.eaglercraft.v1_8.ArrayUtils; +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; +import net.lax1dude.eaglercraft.v1_8.socket.HandshakePacketTypes; +import net.minecraft.network.PacketBuffer; + +public class HandshakerV4 extends HandshakerV3 { + + public HandshakerV4(HandshakerHandler handler) { + super(handler); + } + + @Override + protected int getVersion() { + return 4; + } + + @Override + protected void sendClientRequestLogin(String username, String requestedServer, byte[] password, + boolean enableCookies, byte[] cookie) { + PacketBuffer buffer = new PacketBuffer(Unpooled.buffer()); + buffer.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_REQUEST_LOGIN); + buffer.writeByte(username.length()); + HandshakerHandler.writeASCII(buffer, username); + buffer.writeByte(requestedServer.length()); + HandshakerHandler.writeASCII(buffer, requestedServer); + if(password != null) { + buffer.writeByte(password.length); + buffer.writeBytes(password); + }else { + buffer.writeByte(0); + } + buffer.writeBoolean(enableCookies); + if(enableCookies && cookie != null) { + buffer.writeByte(cookie.length); + buffer.writeBytes(cookie); + }else { + buffer.writeByte(0); + } + handler.websocket.send(buffer.toBytes()); + } + + @Override + protected void handleInboundServerAllowLogin(PacketBuffer buffer) { + byte[] username = new byte[buffer.readUnsignedByte()]; + buffer.readBytes(username); + EaglercraftUUID uuid = new EaglercraftUUID(buffer.readLong(), buffer.readLong()); + handleServerAllowLogin(ArrayUtils.asciiString(username), uuid, ServerCapabilities.VIRTUAL_V4_SERVER_CAPS, + ServerCapabilities.VIRTUAL_V4_SERVER_CAPS_VERS, null); + } + + @Override + protected void sendClientProfileData(Map profileDataToSend) { + List> toSend = new ArrayList<>(profileDataToSend.entrySet()); + PacketBuffer buffer = new PacketBuffer(Unpooled.buffer()); + while(!toSend.isEmpty()) { + int sendLen = 2; + buffer.writerIndex(0); + buffer.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_PROFILE_DATA); + buffer.writeByte(0); // will be replaced + int packetCount = 0; + while(!toSend.isEmpty() && packetCount < 255) { + Entry etr = toSend.get(toSend.size() - 1); + int i = 3 + etr.getKey().length() + etr.getValue().length; + if(sendLen + i < 0xFF00) { + String profileDataType = etr.getKey(); + buffer.writeByte(profileDataType.length()); + HandshakerHandler.writeASCII(buffer, profileDataType); + byte[] data = etr.getValue(); + buffer.writeShort(data.length); + buffer.writeBytes(data); + toSend.remove(toSend.size() - 1); + ++packetCount; + }else { + break; + } + } + byte[] send = buffer.toBytes(); + send[1] = (byte)packetCount; + handler.websocket.send(send); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerV5.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerV5.java new file mode 100644 index 00000000..1d6cea51 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/HandshakerV5.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake; + +import java.nio.charset.StandardCharsets; + +import com.carrotsearch.hppc.ObjectByteHashMap; +import com.carrotsearch.hppc.ObjectByteMap; + +import net.lax1dude.eaglercraft.v1_8.ArrayUtils; +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; +import net.lax1dude.eaglercraft.v1_8.socket.HandshakePacketTypes; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake.ClientCapabilities.ExtCapability; +import net.minecraft.network.PacketBuffer; + +public class HandshakerV5 extends HandshakerV4 { + + public HandshakerV5(HandshakerHandler handler) { + super(handler); + } + + @Override + protected int getVersion() { + return 5; + } + + @Override + protected void sendClientRequestLogin(String username, String requestedServer, byte[] password, + boolean enableCookies, byte[] cookie) { + PacketBuffer buffer = new PacketBuffer(Unpooled.buffer()); + buffer.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_REQUEST_LOGIN); + if(handler.nicknameSelection) { + buffer.writeByte(username.length()); + HandshakerHandler.writeASCII(buffer, username); + }else { + buffer.writeByte(0); + } + buffer.writeByte(requestedServer.length()); + HandshakerHandler.writeASCII(buffer, requestedServer); + if(password != null) { + buffer.writeByte(password.length); + buffer.writeBytes(password); + }else { + buffer.writeByte(0); + } + buffer.writeBoolean(enableCookies); + if(enableCookies && cookie != null) { + buffer.writeByte(cookie.length); + buffer.writeBytes(cookie); + }else { + buffer.writeByte(0); + } + ClientCapabilities caps = ClientCapabilities.createCapabilities(enableCookies); + buffer.writeVarIntToBuffer(caps.getStandardCaps()); + int[] vers = caps.getStandardCapsVers(); + for(int i = 0; i < vers.length; ++i) { + buffer.writeVarIntToBuffer(vers[i]); + } + ExtCapability[] extVers = caps.getExtendedCaps(); + buffer.writeByte(extVers.length); + for(int i = 0; i < extVers.length; ++i) { + ExtCapability extCap = extVers[i]; + buffer.writeLong(extCap.uuid.msb); + buffer.writeLong(extCap.uuid.lsb); + buffer.writeVarIntToBuffer(extCap.vers); + } + handler.websocket.send(buffer.toBytes()); + } + + @Override + protected void handleInboundServerAllowLogin(PacketBuffer buffer) { + byte[] username = new byte[buffer.readUnsignedByte()]; + buffer.readBytes(username); + EaglercraftUUID uuid = new EaglercraftUUID(buffer.readLong(), buffer.readLong()); + int standardCaps = buffer.readVarIntFromBuffer(); + byte[] standardCapsVers = new byte[Integer.bitCount(standardCaps)]; + buffer.readBytes(standardCapsVers); + int extCaps = buffer.readUnsignedByte(); + ObjectByteMap extCapsMap = null; + if(extCaps > 0) { + extCapsMap = new ObjectByteHashMap<>(extCaps); + for (int i = 0; i < extCaps; ++i) { + extCapsMap.put(new EaglercraftUUID(buffer.readLong(), buffer.readLong()), buffer.readByte()); + } + } + handleServerAllowLogin(ArrayUtils.asciiString(username), uuid, standardCaps, standardCapsVers, extCapsMap); + } + + @Override + protected void handleInboundServerRedirectTo(PacketBuffer buffer) { + byte[] urlLen = new byte[buffer.readShort()]; + buffer.readBytes(urlLen); + handleServerRedirectTo(new String(urlLen, StandardCharsets.UTF_8)); + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/ServerCapabilities.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/ServerCapabilities.java new file mode 100644 index 00000000..9469c50b --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/ServerCapabilities.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake; + +import com.carrotsearch.hppc.ObjectByteMap; + +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; + +public class ServerCapabilities { + + static final int VIRTUAL_V3_SERVER_CAPS = (1 << StandardCaps.UPDATE) | (1 << StandardCaps.VOICE); + static final byte[] VIRTUAL_V3_SERVER_CAPS_VERS = new byte[] { 0, 0 }; + + static final int VIRTUAL_V4_SERVER_CAPS = (1 << StandardCaps.UPDATE) | (1 << StandardCaps.VOICE) + | (1 << StandardCaps.REDIRECT) | (1 << StandardCaps.NOTIFICATION) | (1 << StandardCaps.PAUSE_MENU) + | (1 << StandardCaps.WEBVIEW) | (1 << StandardCaps.COOKIE); + static final byte[] VIRTUAL_V4_SERVER_CAPS_VERS = new byte[] { 0, 0, 0, 0, 0, 0 }; + + private final int standardCaps; + private final byte[] standardCapVers; + private final ObjectByteMap extendedCaps; + + public ServerCapabilities(int standardCaps, byte[] standardCapVers, ObjectByteMap extendedCaps) { + this.standardCaps = standardCaps; + this.standardCapVers = standardCapVers; + this.extendedCaps = extendedCaps; + } + + public boolean hasCapability(int cap, int ver) { + int bit = 1 << cap; + if((standardCaps & bit) != 0) { + int versIndex = Integer.bitCount(standardCaps & (bit - 1)); + if(versIndex < standardCapVers.length) { + return (standardCapVers[versIndex] & 0xFF) >= ver; + } + } + return false; + } + + public int getCapability(int cap) { + int bit = 1 << cap; + if((standardCaps & bit) != 0) { + int versIndex = Integer.bitCount(standardCaps & (bit - 1)); + if(versIndex < standardCapVers.length) { + return standardCapVers[versIndex] & 0xFF; + } + } + return -1; + } + + public int getExtCapability(EaglercraftUUID uuid) { + if(extendedCaps != null) { + int idx = extendedCaps.indexOf(uuid); + if(idx >= 0) { + return (int) extendedCaps.indexGet(idx) & 0xFF; + } + } + return -1; + } + + public static ServerCapabilities getLAN() { + return new ServerCapabilities(VIRTUAL_V3_SERVER_CAPS, VIRTUAL_V3_SERVER_CAPS_VERS, null); + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/StandardCaps.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/StandardCaps.java new file mode 100644 index 00000000..526e4ed2 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/handshake/StandardCaps.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake; + +public class StandardCaps { + + public static final int UPDATE = 0; + + public static final int VOICE = 1; + + public static final int REDIRECT = 2; + + public static final int NOTIFICATION = 3; + + public static final int PAUSE_MENU = 4; + + public static final int WEBVIEW = 5; + + public static final int COOKIE = 6; + + // reserved + public static final int EAGLER_IP = 7; + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/InjectedMessageController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/InjectedMessageController.java new file mode 100644 index 00000000..e4049cba --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/InjectedMessageController.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.message; + +import java.io.IOException; +import java.util.List; + +import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; +import net.lax1dude.eaglercraft.v1_8.log4j.Logger; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePacketOutputBuffer; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.ReusableByteArrayInputStream; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.ReusableByteArrayOutputStream; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SimpleInputBufferImpl; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SimpleOutputBufferImpl; + +public class InjectedMessageController extends MessageController { + + private static final Logger logger = LogManager.getLogger("InjectedMessageController"); + + private final ReusableByteArrayInputStream byteInputStreamSingleton = new ReusableByteArrayInputStream(); + private final ReusableByteArrayOutputStream byteOutputStreamSingleton = new ReusableByteArrayOutputStream(); + private final SimpleInputBufferImpl inputStreamSingleton = new SimpleInputBufferImpl(byteInputStreamSingleton); + private final SimpleOutputBufferImpl outputStreamSingleton = new SimpleOutputBufferImpl(byteOutputStreamSingleton); + + public interface IBinarySendFunction { + void sendBinaryFrame(byte[] contents); + } + + private final IBinarySendFunction send; + + public InjectedMessageController(GamePluginMessageProtocol protocol, GameMessageHandler handler, int direction, + IBinarySendFunction send) { + super(protocol, handler, direction); + this.send = send; + } + + public boolean handlePacket(byte[] data, int offset) throws IOException { + if(data.length - offset > 1 && data[offset] == (byte) 0xEE) { + GameMessagePacket pkt; + byteInputStreamSingleton.feedBuffer(data, offset); + inputStreamSingleton.readByte(); + if(data[offset + 1] == (byte) 0xFF) { + inputStreamSingleton.readByte(); + int count = inputStreamSingleton.readVarInt(); + for(int i = 0, j, k; i < count; ++i) { + j = inputStreamSingleton.readVarInt(); + inputStreamSingleton.setToByteArrayReturns(j - 1); + k = byteInputStreamSingleton.getReaderIndex() + j; + if(j < 0 || j > inputStreamSingleton.available()) { + throw new IOException("Packet fragment is too long: " + j + " > " + inputStreamSingleton.available()); + } + pkt = protocol.readPacketV5(receiveDirection, inputStreamSingleton); + if(byteInputStreamSingleton.getReaderIndex() != k) { + throw new IOException("Packet fragment was the wrong length: " + (j + byteInputStreamSingleton.getReaderIndex() - k) + " != " + j); + } + handlePacket(pkt); + } + if(inputStreamSingleton.available() > 0) { + throw new IOException("Leftover data after reading multi-packet! (" + inputStreamSingleton.available() + " bytes)"); + } + byteOutputStreamSingleton.feedBuffer(null); + return true; + } + inputStreamSingleton.setToByteArrayReturns(data.length - offset - 2); + pkt = protocol.readPacketV5(receiveDirection, inputStreamSingleton); + if(byteInputStreamSingleton.available() != 0) { + throw new IOException("Packet was the wrong length: " + pkt.getClass().getSimpleName()); + } + byteOutputStreamSingleton.feedBuffer(null); + handlePacket(pkt); + return true; + } + return false; + } + + @Override + protected void writePacket(GameMessagePacket packet) throws IOException { + int len = packet.length() + 2; + byteOutputStreamSingleton.feedBuffer(len == 1 ? new byte[64] : new byte[len]); + byteOutputStreamSingleton.write(0xEE); + protocol.writePacketV5(sendDirection, outputStreamSingleton, packet); + byte[] data = byteOutputStreamSingleton.returnBuffer(); + byteOutputStreamSingleton.feedBuffer(null); + if(len != 1 && data.length != len) { + logger.warn("Packet " + packet.getClass().getSimpleName() + " was the wrong length after serialization, " + + data.length + " != " + len); + } + send.sendBinaryFrame(data); + } + + @Override + protected void writeMultiPacket(List packets) throws IOException { + int total = packets.size(); + byte[][] buffer = new byte[total][]; + byte[] dat; + for(int i = 0; i < total; ++i) { + GameMessagePacket packet = packets.get(i); + int len = packet.length() + 2; + byteOutputStreamSingleton.feedBuffer(len == 1 ? new byte[64] : new byte[len]); + byteOutputStreamSingleton.write(0xEE); + protocol.writePacketV5(sendDirection, outputStreamSingleton, packet); + dat = byteOutputStreamSingleton.returnBuffer(); + byteOutputStreamSingleton.feedBuffer(null); + if(len != 1 && dat.length != len) { + logger.warn("Packet " + packet.getClass().getSimpleName() + + " was the wrong length after serialization, " + dat.length + " != " + len); + } + buffer[i] = dat; + } + int start = 0; + int i, j, sendCount, totalLen, lastLen; + while(total > start) { + sendCount = 0; + totalLen = 0; + do { + i = buffer[start + sendCount].length - 1; + lastLen = GamePacketOutputBuffer.getVarIntSize(i) + i; + totalLen += lastLen; + ++sendCount; + }while(totalLen < 32760 && sendCount < total - start); + if(totalLen >= 32760) { + --sendCount; + totalLen -= lastLen; + } + if(sendCount <= 1) { + send.sendBinaryFrame(buffer[start++]); + continue; + } + byteOutputStreamSingleton.feedBuffer(new byte[2 + totalLen + GamePacketOutputBuffer.getVarIntSize(sendCount)]); + outputStreamSingleton.writeShort(0xEEFF); + outputStreamSingleton.writeVarInt(sendCount); + for(j = 0; j < sendCount; ++j) { + dat = buffer[start++]; + i = dat.length - 1; + outputStreamSingleton.writeVarInt(i); + outputStreamSingleton.write(dat, 1, i); + } + send.sendBinaryFrame(byteOutputStreamSingleton.returnBuffer()); + byteOutputStreamSingleton.feedBuffer(null); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/LegacyMessageController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/LegacyMessageController.java new file mode 100644 index 00000000..8b955ce1 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/LegacyMessageController.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.message; + +import java.io.IOException; +import java.util.List; + +import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; +import net.lax1dude.eaglercraft.v1_8.log4j.Logger; +import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePacketOutputBuffer; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; +import net.minecraft.network.PacketBuffer; + +public class LegacyMessageController extends MessageController { + + private static final Logger logger = LogManager.getLogger("LegacyMessageController"); + + public interface IPluginMessageSendFunction { + void sendPluginMessage(String channel, PacketBuffer contents); + } + + private final PacketBufferInputWrapper inputStream = new PacketBufferInputWrapper(null); + private final PacketBufferOutputWrapper outputStream = new PacketBufferOutputWrapper(null); + private final IPluginMessageSendFunction send; + + public LegacyMessageController(GamePluginMessageProtocol protocol, GameMessageHandler handler, int direction, + IPluginMessageSendFunction send) { + super(protocol, handler, direction); + this.send = send; + } + + public boolean handlePacket(String channel, PacketBuffer data) throws IOException { + GameMessagePacket pkt; + if(protocol.ver >= 4 && data.readableBytes() > 0 && data.getByte(data.readerIndex()) == (byte) 0xFF + && channel.equals(GamePluginMessageConstants.V4_CHANNEL)) { + data.readByte(); + inputStream.buffer = data; + int count = inputStream.readVarInt(); + for(int i = 0, j, k, l; i < count; ++i) { + j = data.readVarIntFromBuffer(); + k = data.readerIndex() + j; + l = data.writerIndex(); + if(j < 0 || k > l) { + throw new IOException("Packet fragment is too long: " + j + " > " + data.readableBytes()); + } + data.writerIndex(k); + pkt = protocol.readPacket(channel, receiveDirection, inputStream); + if(pkt != null) { + handlePacket(pkt); + }else { + logger.warn("Could not read packet fragment {} of {}, unknown packet", count, i); + } + if(data.readerIndex() != k) { + logger.warn("Packet fragment {} was the wrong length: {} != {}", + (pkt != null ? pkt.getClass().getSimpleName() : "unknown"), j + data.readerIndex() - k, j); + data.readerIndex(k); + } + data.writerIndex(l); + } + if(data.readableBytes() > 0) { + logger.warn("Leftover data after reading multi-packet! ({} bytes)", data.readableBytes()); + } + inputStream.buffer = null; + return true; + } + inputStream.buffer = data; + pkt = protocol.readPacket(channel, receiveDirection, inputStream); + if(pkt != null && inputStream.available() > 0) { + logger.warn("Leftover data after reading packet {}! ({} bytes)", pkt.getClass().getSimpleName(), inputStream.available()); + } + inputStream.buffer = null; + if(pkt != null) { + handlePacket(pkt); + return true; + }else { + return false; + } + } + + @Override + protected void writePacket(GameMessagePacket packet) throws IOException { + int len = packet.length() + 1; + PacketBuffer buf = new PacketBuffer(len != 0 ? Unpooled.buffer(len) : Unpooled.buffer(64)); + outputStream.buffer = buf; + String chan = protocol.writePacket(sendDirection, outputStream, packet); + outputStream.buffer = null; + int j = buf.writerIndex(); + if(len != 0 && j != len && (protocol.ver > 3 || j + 1 != len)) { + logger.warn("Packet {} was expected to be {} bytes but was serialized to {} bytes!", + packet.getClass().getSimpleName(), len, j); + } + send.sendPluginMessage(chan, buf); + } + + @Override + protected void writeMultiPacket(List packets) throws IOException { + int total = packets.size(); + PacketBuffer[] toSend = new PacketBuffer[total]; + for(int i = 0; i < total; ++i) { + GameMessagePacket packet = packets.get(i); + int len = packet.length() + 1; + PacketBuffer buf = new PacketBuffer(len != 0 ? Unpooled.buffer(len) : Unpooled.buffer(64)); + outputStream.buffer = buf; + protocol.writePacket(sendDirection, outputStream, packet); + outputStream.buffer = null; + int j = buf.writerIndex(); + if(len != 0 && j != len && (protocol.ver > 3 || j + 1 != len)) { + logger.warn("Packet {} was expected to be {} bytes but was serialized to {} bytes!", + packet.getClass().getSimpleName(), len, j); + } + toSend[i] = buf; + } + int start = 0; + int i, j, sendCount, totalLen, lastLen; + while(total > start) { + sendCount = 0; + totalLen = 0; + do { + i = toSend[start + sendCount].readableBytes(); + lastLen = GamePacketOutputBuffer.getVarIntSize(i) + i; + totalLen += lastLen; + ++sendCount; + }while(totalLen < 32760 && sendCount < total - start); + if(totalLen >= 32760) { + --sendCount; + totalLen -= lastLen; + } + if(sendCount <= 1) { + send.sendPluginMessage(GamePluginMessageConstants.V4_CHANNEL, toSend[start++]); + continue; + } + PacketBuffer sendBuffer = new PacketBuffer( + Unpooled.buffer(1 + totalLen + GamePacketOutputBuffer.getVarIntSize(sendCount))); + sendBuffer.writerIndex(0); + sendBuffer.writeByte(0xFF); + sendBuffer.writeVarIntToBuffer(sendCount); + for(j = 0; j < sendCount; ++j) { + PacketBuffer dat = toSend[start++]; + sendBuffer.writeVarIntToBuffer(dat.readableBytes()); + sendBuffer.writeBytes(dat); + } + send.sendPluginMessage(GamePluginMessageConstants.V4_CHANNEL, sendBuffer); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/MessageController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/MessageController.java new file mode 100644 index 00000000..7a93bc51 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/MessageController.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.socket.protocol.message; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import net.lax1dude.eaglercraft.v1_8.EagRuntime; +import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; +import net.lax1dude.eaglercraft.v1_8.log4j.Logger; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; + +public abstract class MessageController { + + private static final Logger logger = LogManager.getLogger("MessageController"); + + protected final GamePluginMessageProtocol protocol; + protected final GameMessageHandler handler; + protected final int sendDirection; + protected final int receiveDirection; + protected List sendQueue; + + public MessageController(GamePluginMessageProtocol protocol, GameMessageHandler handler, int direction) { + this.protocol = protocol; + this.handler = handler; + this.sendDirection = direction; + this.receiveDirection = direction == GamePluginMessageConstants.CLIENT_TO_SERVER + ? GamePluginMessageConstants.SERVER_TO_CLIENT + : GamePluginMessageConstants.CLIENT_TO_SERVER; + this.sendQueue = protocol.ver >= 4 && !EagRuntime.getConfiguration().isEaglerNoDelay() + ? new ArrayList<>() : null; + } + + public GamePluginMessageProtocol getProtocol() { + return protocol; + } + + public boolean isSendQueueEnabled() { + return sendQueue != null; + } + + public void sendPacket(GameMessagePacket packet) { + if(sendQueue != null) { + sendQueue.add(packet); + }else { + try { + writePacket(packet); + } catch (IOException ex) { + throw new RuntimeException("Failed to serialize packet: " + packet.getClass().getSimpleName(), ex); + } + } + } + + protected abstract void writePacket(GameMessagePacket packet) throws IOException; + + public void flush() { + if(sendQueue != null && !sendQueue.isEmpty()) { + try { + writeMultiPacket(sendQueue); + } catch (IOException ex) { + throw new RuntimeException("Failed to serialize packet multi-packet!", ex); + } + if(sendQueue.size() < 64) { + sendQueue.clear(); + }else { + sendQueue = new ArrayList<>(); + } + } + } + + protected abstract void writeMultiPacket(List packets) throws IOException; + + protected void handlePacket(GameMessagePacket packet) { + try { + packet.handlePacket(handler); + }catch(Throwable t) { + logger.error("Failed to handle packet {} in direction {} using handler {}!", packet.getClass().getSimpleName(), + GamePluginMessageConstants.getDirectionString(receiveDirection), handler); + logger.error(t); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferInputWrapper.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/PacketBufferInputWrapper.java similarity index 99% rename from sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferInputWrapper.java rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/PacketBufferInputWrapper.java index a281bb04..e274c995 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferInputWrapper.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/PacketBufferInputWrapper.java @@ -14,7 +14,7 @@ * */ -package net.lax1dude.eaglercraft.v1_8.socket.protocol.client; +package net.lax1dude.eaglercraft.v1_8.socket.protocol.message; import java.io.DataInputStream; import java.io.EOFException; diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferOutputWrapper.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/PacketBufferOutputWrapper.java similarity index 99% rename from sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferOutputWrapper.java rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/PacketBufferOutputWrapper.java index 7c17b5ac..ef56584b 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferOutputWrapper.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/message/PacketBufferOutputWrapper.java @@ -14,7 +14,7 @@ * */ -package net.lax1dude.eaglercraft.v1_8.socket.protocol.client; +package net.lax1dude.eaglercraft.v1_8.socket.protocol.message; import java.io.IOException; import java.io.OutputStream; diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnecting.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnecting.java index adddfb24..521fdbc2 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnecting.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnecting.java @@ -19,7 +19,7 @@ package net.lax1dude.eaglercraft.v1_8.sp.gui; import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion; import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC; import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile; -import net.lax1dude.eaglercraft.v1_8.socket.ConnectionHandshake; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake.HandshakerHandler; import net.lax1dude.eaglercraft.v1_8.sp.lan.LANClientNetworkManager; import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager; import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServer; @@ -101,8 +101,11 @@ public class GuiScreenLANConnecting extends GuiScreen { if(++renderCount > 1) { RelayServerSocket sock; if(relay == null) { - sock = RelayManager.relayManager.getWorkingRelay((str) -> ls.resetProgressAndMessage("Connecting: " + str), 0x02, code); + ls.resetProgressAndMessage("Connecting to '" + code + "'..."); + sock = RelayManager.relayManager.getWorkingRelay((str) -> ls.displayLoadingString("Connecting: " + str), 0x02, code); }else { + ls.resetProgressAndMessage("Connecting to '" + code + "'..."); + ls.displayLoadingString("Connecting: " + relay.address); sock = RelayManager.relayManager.connectHandshake(relay, 0x02, code); } if(sock == null) { @@ -125,7 +128,7 @@ public class GuiScreenLANConnecting extends GuiScreen { networkManager.setNetHandler(new NetHandlerSingleplayerLogin(networkManager, mc, parent)); networkManager.sendPacket(new C00PacketLoginStart(this.mc.getSession().getProfile(), EaglerProfile.getSkinPacket(3), EaglerProfile.getCapePacket(), - ConnectionHandshake.getSPHandshakeProtocolData(), EaglercraftVersion.clientBrandUUID)); + HandshakerHandler.getSPHandshakeProtocolData(), EaglercraftVersion.clientBrandUUID)); } } } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenSingleplayerConnecting.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenSingleplayerConnecting.java index c7bffc47..34cc6bc5 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenSingleplayerConnecting.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenSingleplayerConnecting.java @@ -21,7 +21,7 @@ import java.io.IOException; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion; import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile; -import net.lax1dude.eaglercraft.v1_8.socket.ConnectionHandshake; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake.HandshakerHandler; import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController; import net.lax1dude.eaglercraft.v1_8.sp.socket.ClientIntegratedServerNetworkManager; import net.lax1dude.eaglercraft.v1_8.sp.socket.NetHandlerSingleplayerLogin; @@ -94,7 +94,7 @@ public class GuiScreenSingleplayerConnecting extends GuiScreen { this.networkManager.setNetHandler(new NetHandlerSingleplayerLogin(this.networkManager, this.mc, this.menu)); this.networkManager.sendPacket(new C00PacketLoginStart(this.mc.getSession().getProfile(), EaglerProfile.getSkinPacket(3), EaglerProfile.getCapePacket(), - ConnectionHandshake.getSPHandshakeProtocolData(), EaglercraftVersion.clientBrandUUID)); + HandshakerHandler.getSPHandshakeProtocolData(), EaglercraftVersion.clientBrandUUID)); } try { this.networkManager.processReceivedPackets(); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java index 0f2f5c18..7b3c5b56 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -366,6 +366,10 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager { } } + if(injectedController != null && injectedController.handlePacket(fullData, off)) { + continue; + } + ByteBuf nettyBuffer = Unpooled.buffer(fullData, fullData.length); nettyBuffer.writerIndex(fullData.length); nettyBuffer.readerIndex(off); @@ -399,6 +403,32 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager { } } + @Override + public void injectRawFrame(byte[] data) { + if(!isChannelOpen()) { + logger.error("Frame was injected on a closed connection"); + return; + } + int len = data.length; + int fragmentSizeN1 = fragmentSize - 1; + if(len > fragmentSizeN1) { + int idx = 0; + do { + int readLen = len > fragmentSizeN1 ? fragmentSizeN1 : len; + byte[] frag = new byte[readLen + 1]; + System.arraycopy(data, idx, frag, 1, readLen); + idx += readLen; + len -= readLen; + frag[0] = len == 0 ? (byte)0 : (byte)1; + PlatformWebRTC.clientLANSendPacket(frag); + }while(len > 0); + }else { + byte[] bytes = new byte[len + 1]; + System.arraycopy(data, 0, bytes, 1, len); + PlatformWebRTC.clientLANSendPacket(bytes); + } + } + @Override public void closeChannel(IChatComponent reason) { if(!PlatformWebRTC.clientLANClosed()) { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerIntegratedServerWorker.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerIntegratedServerWorker.java index f916e8e1..2f9b45e1 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerIntegratedServerWorker.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerIntegratedServerWorker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024 lax1dude, ayunami2000. All Rights Reserved. + * Copyright (c) 2023-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerMinecraftServer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerMinecraftServer.java index a2a83cc7..ab76d439 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerMinecraftServer.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerMinecraftServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024 lax1dude, ayunami2000. All Rights Reserved. + * Copyright (c) 2023-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -23,6 +23,7 @@ import java.util.List; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.EagRuntime; +import net.lax1dude.eaglercraft.v1_8.EagUtils; import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; import net.minecraft.entity.player.EntityPlayer; @@ -33,8 +34,7 @@ import net.minecraft.world.EnumDifficulty; import net.minecraft.world.WorldServer; import net.minecraft.world.WorldSettings; import net.minecraft.world.WorldSettings.GameType; -import net.lax1dude.eaglercraft.v1_8.sp.server.skins.IntegratedCapeService; -import net.lax1dude.eaglercraft.v1_8.sp.server.skins.IntegratedSkinService; +import net.lax1dude.eaglercraft.v1_8.sp.server.skins.IntegratedTextureService; import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService; public class EaglerMinecraftServer extends MinecraftServer { @@ -48,8 +48,7 @@ public class EaglerMinecraftServer extends MinecraftServer { protected WorldSettings newWorldSettings; protected boolean paused; protected EaglerSaveHandler saveHandler; - protected IntegratedSkinService skinService; - protected IntegratedCapeService capeService; + protected IntegratedTextureService textureService; protected IntegratedVoiceService voiceService; private long lastTPSUpdate = 0l; @@ -67,25 +66,22 @@ public class EaglerMinecraftServer extends MinecraftServer { super(world); Bootstrap.register(); this.saveHandler = new EaglerSaveHandler(savesDir, world); - this.skinService = new IntegratedSkinService(WorldsDB.newVFile(saveHandler.getWorldDirectory(), "eagler/skulls")); - this.capeService = new IntegratedCapeService(); + EaglerPlayerList playerList = new EaglerPlayerList(this, viewDistance); + this.textureService = new IntegratedTextureService(playerList, + WorldsDB.newVFile(saveHandler.getWorldDirectory(), "eagler/skulls")); this.voiceService = null; this.setServerOwner(owner); logger.info("server owner: " + owner); this.setDemo(demo); this.canCreateBonusChest(currentWorldSettings != null && currentWorldSettings.isBonusChestEnabled()); this.setBuildLimit(256); - this.setConfigManager(new EaglerPlayerList(this, viewDistance)); + this.setConfigManager(playerList); this.newWorldSettings = currentWorldSettings; this.paused = false; } - public IntegratedSkinService getSkinService() { - return skinService; - } - - public IntegratedCapeService getCapeService() { - return capeService; + public IntegratedTextureService getTextureService() { + return textureService; } public IntegratedVoiceService getVoiceService() { @@ -166,12 +162,14 @@ public class EaglerMinecraftServer extends MinecraftServer { this.currentTime += 50l; this.tick(); ++counterTicksPerSecond; + } else if (!singleThreadMode) { + EagUtils.sleep(1); } } } public void updateTimeLightAndEntities() { - this.skinService.flushCache(); + this.textureService.flushCache(); super.updateTimeLightAndEntities(); } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerPlayerList.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerPlayerList.java index 257ba378..21480f76 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerPlayerList.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerPlayerList.java @@ -44,8 +44,5 @@ public class EaglerPlayerList extends ServerConfigurationManager { public void playerLoggedOut(EntityPlayerMP playerIn) { super.playerLoggedOut(playerIn); - EaglerMinecraftServer svr = (EaglerMinecraftServer)getServerInstance(); - svr.skinService.unregisterPlayer(playerIn.getUniqueID()); - svr.capeService.unregisterPlayer(playerIn.getUniqueID()); } } \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullData.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullData.java index 5c9ee20c..51e0fc77 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullData.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. + * Copyright (c) 2023-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -17,35 +17,56 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.skins; import net.lax1dude.eaglercraft.v1_8.EagRuntime; -import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV3EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV4EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV5EAG; import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache; public class CustomSkullData { - public String skinURL; - public long lastHit; - public SkinPacketVersionCache skinData; + protected long lastHit; + protected byte[] textureDataV3; + protected byte[] textureDataV4; - public CustomSkullData(String skinURL, byte[] skinData) { - this.skinURL = skinURL; - this.lastHit = EagRuntime.steadyTimeMillis(); + public CustomSkullData(byte[] skinData) { if(skinData.length != 16384) { byte[] fixed = new byte[16384]; System.arraycopy(skinData, 0, fixed, 0, skinData.length > fixed.length ? fixed.length : skinData.length); skinData = fixed; } - this.skinData = SkinPacketVersionCache.createCustomV3(0l, 0l, 0, skinData); + textureDataV3 = skinData; + lastHit = EagRuntime.steadyTimeMillis(); } public byte[] getFullSkin() { - return ((SPacketOtherSkinCustomV3EAG)skinData.getV3()).customSkin; + return textureDataV3; } - public GameMessagePacket getSkinPacket(EaglercraftUUID uuid, GamePluginMessageProtocol protocol) { - return SkinPacketVersionCache.rewriteUUID(skinData.get(protocol), uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()); + public GameMessagePacket getSkin(long uuidMost, long uuidLeast, GamePluginMessageProtocol protocol) { + switch(protocol) { + case V3: + return new SPacketOtherSkinCustomV3EAG(uuidMost, uuidLeast, 0xFF, textureDataV3); + case V4: + if(textureDataV4 == null) { + textureDataV4 = SkinPacketVersionCache.convertToV4Raw(textureDataV3); + } + return new SPacketOtherSkinCustomV4EAG(uuidMost, uuidLeast, 0xFF, textureDataV4); + default: + throw new IllegalStateException(); + } + } + + public GameMessagePacket getSkinV5(int requestId, GamePluginMessageProtocol protocol) { + if(protocol.ver >= 5) { + if(textureDataV4 == null) { + textureDataV4 = SkinPacketVersionCache.convertToV4Raw(textureDataV3); + } + return new SPacketOtherSkinCustomV5EAG(requestId, 0xFF, textureDataV4); + }else { + throw new IllegalStateException(); + } } } \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullLoader.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullLoader.java new file mode 100644 index 00000000..9ba45d9b --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullLoader.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.sp.server.skins; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import net.lax1dude.eaglercraft.v1_8.EagRuntime; +import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest; +import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2; +import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB; + +public class CustomSkullLoader { + + private static final byte[] skullNotFoundTexture = new byte[4096]; + + static { + for(int y = 0; y < 16; ++y) { + for(int x = 0; x < 64; ++x) { + int i = (y << 8) | (x << 2); + byte j = ((x + y) & 1) == 1 ? (byte)255 : 0; + skullNotFoundTexture[i] = (byte)255; + skullNotFoundTexture[i + 1] = j; + skullNotFoundTexture[i + 2] = 0; + skullNotFoundTexture[i + 3] = j; + } + } + } + + private final VFile2 folder; + + private final Map customSkulls = new HashMap<>(64); + + private long lastFlush = 0l; + + public CustomSkullLoader(VFile2 folder) { + this.folder = folder; + } + + private CustomSkullData loadSkullData0(String urlStr) { + byte[] data = WorldsDB.newVFile(folder, urlStr).getAllBytes(); + if(data == null) { + return new CustomSkullData(skullNotFoundTexture); + }else { + return new CustomSkullData(data); + } + } + + public CustomSkullData loadSkullData(String url) { + CustomSkullData sk = customSkulls.get(url); + if(sk == null) { + customSkulls.put(url, sk = loadSkullData0(url)); + }else { + sk.lastHit = EagRuntime.steadyTimeMillis(); + } + return sk; + } + + private static final String hex = "0123456789abcdef"; + + public String installNewSkull(byte[] skullData) { + // set to 16384 to save a full 64x64 skin + if(skullData.length > 4096) { + byte[] tmp = skullData; + skullData = new byte[4096]; + System.arraycopy(tmp, 0, skullData, 0, 4096); + } + SHA1Digest sha = new SHA1Digest(); + sha.update(skullData, 0, skullData.length); + byte[] hash = new byte[20]; + sha.doFinal(hash, 0); + char[] hashText = new char[40]; + for(int i = 0; i < 20; ++i) { + hashText[i << 1] = hex.charAt((hash[i] & 0xF0) >> 4); + hashText[(i << 1) + 1] = hex.charAt(hash[i] & 0x0F); + } + String str = "skin-" + new String(hashText) + ".bmp"; + customSkulls.put(str, new CustomSkullData(skullData)); + WorldsDB.newVFile(folder, str).setAllBytes(skullData); + return str; + } + + public void flushCache() { + long cur = EagRuntime.steadyTimeMillis(); + if(cur - lastFlush > 300000l) { + lastFlush = cur; + Iterator customSkullsItr = customSkulls.values().iterator(); + while(customSkullsItr.hasNext()) { + if(cur - customSkullsItr.next().lastHit > 900000l) { + customSkullsItr.remove(); + } + } + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapePackets.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapePackets.java deleted file mode 100644 index 731531d3..00000000 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapePackets.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2024 lax1dude. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -package net.lax1dude.eaglercraft.v1_8.sp.server.skins; - -import java.io.IOException; - -import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapeCustomEAG; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetEAG; - -public class IntegratedCapePackets { - - public static final int PACKET_MY_CAPE_PRESET = 0x01; - public static final int PACKET_MY_CAPE_CUSTOM = 0x02; - - public static void registerEaglerPlayer(EaglercraftUUID clientUUID, byte[] bs, IntegratedCapeService capeService) throws IOException { - if(bs.length == 0) { - throw new IOException("Zero-length packet recieved"); - } - GameMessagePacket generatedPacket; - int packetType = (int)bs[0] & 0xFF; - switch(packetType) { - case PACKET_MY_CAPE_PRESET: - if(bs.length != 5) { - throw new IOException("Invalid length " + bs.length + " for preset cape packet"); - } - generatedPacket = new SPacketOtherCapePresetEAG(clientUUID.msb, clientUUID.lsb, (bs[1] << 24) | (bs[2] << 16) | (bs[3] << 8) | (bs[4] & 0xFF)); - break; - case PACKET_MY_CAPE_CUSTOM: - if(bs.length != 1174) { - throw new IOException("Invalid length " + bs.length + " for custom cape packet"); - } - byte[] capePixels = new byte[bs.length - 1]; - System.arraycopy(bs, 1, capePixels, 0, capePixels.length); - generatedPacket = new SPacketOtherCapeCustomEAG(clientUUID.msb, clientUUID.lsb, capePixels); - break; - default: - throw new IOException("Unknown skin packet type: " + packetType); - } - capeService.registerEaglercraftPlayer(clientUUID, generatedPacket); - } - - public static void registerEaglerPlayerFallback(EaglercraftUUID clientUUID, IntegratedCapeService capeService) { - capeService.registerEaglercraftPlayer(clientUUID, new SPacketOtherCapePresetEAG(clientUUID.msb, clientUUID.lsb, 0)); - } - -} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapeService.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapeService.java deleted file mode 100644 index de99b5fa..00000000 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapeService.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2024 lax1dude. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -package net.lax1dude.eaglercraft.v1_8.sp.server.skins; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; -import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; -import net.lax1dude.eaglercraft.v1_8.log4j.Logger; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetEAG; -import net.minecraft.entity.player.EntityPlayerMP; - -public class IntegratedCapeService { - - public static final Logger logger = LogManager.getLogger("IntegratedCapeService"); - - public static final int masterRateLimitPerPlayer = 250; - - private final Map capesCache = new HashMap<>(); - - public void processLoginPacket(byte[] packetData, EntityPlayerMP sender) { - try { - IntegratedCapePackets.registerEaglerPlayer(sender.getUniqueID(), packetData, this); - } catch (IOException e) { - logger.error("Invalid skin data packet recieved from player {}!", sender.getName()); - logger.error(e); - sender.playerNetServerHandler.kickPlayerFromServer("Invalid skin data packet recieved!"); - } - } - - public void registerEaglercraftPlayer(EaglercraftUUID playerUUID, GameMessagePacket capePacket) { - capesCache.put(playerUUID, capePacket); - } - - public void processGetOtherCape(EaglercraftUUID searchUUID, EntityPlayerMP sender) { - GameMessagePacket maybeCape = capesCache.get(searchUUID); - if(maybeCape == null) { - maybeCape = new SPacketOtherCapePresetEAG(searchUUID.msb, searchUUID.lsb, 0); - } - sender.playerNetServerHandler.sendEaglerMessage(maybeCape); - } - - public void unregisterPlayer(EaglercraftUUID playerUUID) { - synchronized(capesCache) { - capesCache.remove(playerUUID); - } - } -} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinPackets.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinPackets.java deleted file mode 100644 index 61d865f4..00000000 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinPackets.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -package net.lax1dude.eaglercraft.v1_8.sp.server.skins; - -import java.io.IOException; - -import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache; - -public class IntegratedSkinPackets { - - public static final int PACKET_MY_SKIN_PRESET = 0x01; - public static final int PACKET_MY_SKIN_CUSTOM = 0x02; - - public static void registerEaglerPlayer(EaglercraftUUID clientUUID, byte[] bs, IntegratedSkinService skinService, - int protocolVers) throws IOException { - if(bs.length == 0) { - throw new IOException("Zero-length packet recieved"); - } - GameMessagePacket generatedPacketV3 = null; - GameMessagePacket generatedPacketV4 = null; - int skinModel = -1; - int packetType = (int)bs[0] & 0xFF; - switch(packetType) { - case PACKET_MY_SKIN_PRESET: - if(bs.length != 5) { - throw new IOException("Invalid length " + bs.length + " for preset skin packet"); - } - generatedPacketV3 = generatedPacketV4 = new SPacketOtherSkinPresetEAG(clientUUID.msb, clientUUID.lsb, - (bs[1] << 24) | (bs[2] << 16) | (bs[3] << 8) | (bs[4] & 0xFF)); - break; - case PACKET_MY_SKIN_CUSTOM: - if(protocolVers <= 3) { - byte[] pixels = new byte[16384]; - if(bs.length != 2 + pixels.length) { - throw new IOException("Invalid length " + bs.length + " for custom skin packet"); - } - setAlphaForChestV3(pixels); - System.arraycopy(bs, 2, pixels, 0, pixels.length); - generatedPacketV3 = new SPacketOtherSkinCustomV3EAG(clientUUID.msb, clientUUID.lsb, (skinModel = (int)bs[1] & 0xFF), pixels); - }else { - byte[] pixels = new byte[12288]; - if(bs.length != 2 + pixels.length) { - throw new IOException("Invalid length " + bs.length + " for custom skin packet"); - } - setAlphaForChestV4(pixels); - System.arraycopy(bs, 2, pixels, 0, pixels.length); - generatedPacketV4 = new SPacketOtherSkinCustomV4EAG(clientUUID.msb, clientUUID.lsb, (skinModel = (int)bs[1] & 0xFF), pixels); - } - break; - default: - throw new IOException("Unknown skin packet type: " + packetType); - } - skinService.processPacketPlayerSkin(clientUUID, new SkinPacketVersionCache(generatedPacketV3, generatedPacketV4), skinModel); - } - - public static void registerEaglerPlayerFallback(EaglercraftUUID clientUUID, IntegratedSkinService skinService) throws IOException { - int skinModel = (clientUUID.hashCode() & 1) != 0 ? 1 : 0; - skinService.processPacketPlayerSkin(clientUUID, SkinPacketVersionCache.createPreset(clientUUID.msb, clientUUID.lsb, skinModel), skinModel); - } - - public static void setAlphaForChestV3(byte[] skin64x64) { - if(skin64x64.length != 16384) { - throw new IllegalArgumentException("Skin is not 64x64!"); - } - for(int y = 20; y < 32; ++y) { - for(int x = 16; x < 40; ++x) { - skin64x64[(y << 8) | (x << 2)] = (byte)0xFF; - } - } - } - - public static void setAlphaForChestV4(byte[] skin64x64) { - if(skin64x64.length != 12288) { - throw new IllegalArgumentException("Skin is not 64x64!"); - } - for(int y = 20; y < 32; ++y) { - for(int x = 16; x < 40; ++x) { - skin64x64[((y << 6) | x) * 3] |= 0x80; - } - } - } - - public static SPacketOtherSkinPresetEAG makePresetResponse(EaglercraftUUID uuid) { - return new SPacketOtherSkinPresetEAG(uuid.msb, uuid.lsb, (uuid.hashCode() & 1) != 0 ? 1 : 0); - } - - public static byte[] asciiString(String string) { - byte[] str = new byte[string.length()]; - for(int i = 0; i < str.length; ++i) { - str[i] = (byte)string.charAt(i); - } - return str; - } - - public static EaglercraftUUID createEaglerURLSkinUUID(String skinUrl) { - return EaglercraftUUID.nameUUIDFromBytes(asciiString("EaglercraftSkinURL:" + skinUrl)); - } - - public static int getModelId(String modelName) { - return "slim".equalsIgnoreCase(modelName) ? 1 : 0; - } - -} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinService.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinService.java deleted file mode 100644 index 822407fc..00000000 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinService.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -package net.lax1dude.eaglercraft.v1_8.sp.server.skins; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import net.lax1dude.eaglercraft.v1_8.Base64; -import net.lax1dude.eaglercraft.v1_8.EagRuntime; -import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; -import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest; -import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2; -import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; -import net.lax1dude.eaglercraft.v1_8.log4j.Logger; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetEAG; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache; -import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.init.Items; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ChatComponentTranslation; -import net.minecraft.util.EnumChatFormatting; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.nbt.NBTTagString; - -public class IntegratedSkinService { - - public static final Logger logger = LogManager.getLogger("IntegratedSkinService"); - - public static final byte[] skullNotFoundTexture = new byte[4096]; - - static { - for(int y = 0; y < 16; ++y) { - for(int x = 0; x < 64; ++x) { - int i = (y << 8) | (x << 2); - byte j = ((x + y) & 1) == 1 ? (byte)255 : 0; - skullNotFoundTexture[i] = (byte)255; - skullNotFoundTexture[i + 1] = j; - skullNotFoundTexture[i + 2] = 0; - skullNotFoundTexture[i + 3] = j; - } - } - } - - public final VFile2 skullsDirectory; - - public final Map playerSkins = new HashMap<>(); - public final Map customSkulls = new HashMap<>(); - - private long lastFlush = 0l; - - public IntegratedSkinService(VFile2 skullsDirectory) { - this.skullsDirectory = skullsDirectory; - } - - public void processLoginPacket(byte[] packetData, EntityPlayerMP sender, int protocolVers) { - try { - IntegratedSkinPackets.registerEaglerPlayer(sender.getUniqueID(), packetData, this, protocolVers); - } catch (IOException e) { - logger.error("Invalid skin data packet recieved from player {}!", sender.getName()); - logger.error(e); - sender.playerNetServerHandler.kickPlayerFromServer("Invalid skin data packet recieved!"); - } - } - - public void processPacketGetOtherSkin(EaglercraftUUID searchUUID, EntityPlayerMP sender) { - SkinPacketVersionCache playerSkin = playerSkins.get(searchUUID); - GameMessagePacket toSend = null; - if(playerSkin != null) { - toSend = playerSkin.get(sender.playerNetServerHandler.getEaglerMessageProtocol()); - }else { - toSend = IntegratedSkinPackets.makePresetResponse(searchUUID); - } - sender.playerNetServerHandler.sendEaglerMessage(toSend); - } - - public void processPacketGetOtherSkin(EaglercraftUUID searchUUID, String urlStr, EntityPlayerMP sender) { - urlStr = urlStr.toLowerCase(); - GameMessagePacket playerSkin; - if(!urlStr.startsWith("eagler://")) { - playerSkin = new SPacketOtherSkinPresetEAG(searchUUID.msb, searchUUID.lsb, 0); - }else { - urlStr = urlStr.substring(9); - if(urlStr.contains(VFile2.pathSeperator)) { - playerSkin = new SPacketOtherSkinPresetEAG(searchUUID.msb, searchUUID.lsb, 0); - }else { - CustomSkullData sk = customSkulls.get(urlStr); - if(sk == null) { - customSkulls.put(urlStr, sk = loadCustomSkull(urlStr)); - }else { - sk.lastHit = EagRuntime.steadyTimeMillis(); - } - playerSkin = sk.getSkinPacket(searchUUID, sender.playerNetServerHandler.getEaglerMessageProtocol()); - } - } - sender.playerNetServerHandler.sendEaglerMessage(playerSkin); - } - - public void processPacketPlayerSkin(EaglercraftUUID clientUUID, SkinPacketVersionCache generatedPacket, int skinModel) { - playerSkins.put(clientUUID, generatedPacket); - } - - public void unregisterPlayer(EaglercraftUUID clientUUID) { - playerSkins.remove(clientUUID); - } - - public void processPacketInstallNewSkin(byte[] skullData, EntityPlayerMP sender) { - if(!sender.canCommandSenderUseCommand(2, "give")) { - ChatComponentTranslation cc = new ChatComponentTranslation("command.skull.nopermission"); - cc.getChatStyle().setColor(EnumChatFormatting.RED); - sender.addChatMessage(cc); - return; - } - String fileName = "eagler://" + installNewSkull(skullData); - NBTTagCompound rootTagCompound = new NBTTagCompound(); - NBTTagCompound ownerTagCompound = new NBTTagCompound(); - ownerTagCompound.setString("Name", "Eagler"); - ownerTagCompound.setString("Id", EaglercraftUUID.nameUUIDFromBytes((("EaglerSkullUUID:" + fileName).getBytes(StandardCharsets.UTF_8))).toString()); - NBTTagCompound propertiesTagCompound = new NBTTagCompound(); - NBTTagList texturesTagList = new NBTTagList(); - NBTTagCompound texturesTagCompound = new NBTTagCompound(); - String texturesProp = "{\"textures\":{\"SKIN\":{\"url\":\"" + fileName + "\",\"metadata\":{\"model\":\"default\"}}}}"; - texturesTagCompound.setString("Value", Base64.encodeBase64String(texturesProp.getBytes(StandardCharsets.UTF_8))); - texturesTagList.appendTag(texturesTagCompound); - propertiesTagCompound.setTag("textures", texturesTagList); - ownerTagCompound.setTag("Properties", propertiesTagCompound); - rootTagCompound.setTag("SkullOwner", ownerTagCompound); - NBTTagCompound displayTagCompound = new NBTTagCompound(); - displayTagCompound.setString("Name", EnumChatFormatting.RESET + "Custom Eaglercraft Skull"); - NBTTagList loreList = new NBTTagList(); - loreList.appendTag(new NBTTagString(EnumChatFormatting.GRAY + (fileName.length() > 24 ? (fileName.substring(0, 22) + "...") : fileName))); - displayTagCompound.setTag("Lore", loreList); - rootTagCompound.setTag("display", displayTagCompound); - ItemStack stack = new ItemStack(Items.skull, 1, 3); - stack.setTagCompound(rootTagCompound); - boolean flag = sender.inventory.addItemStackToInventory(stack); - if (flag) { - sender.worldObj.playSoundAtEntity(sender, "random.pop", 0.2F, - ((sender.getRNG().nextFloat() - sender.getRNG().nextFloat()) * 0.7F + 1.0F) - * 2.0F); - sender.inventoryContainer.detectAndSendChanges(); - } - sender.addChatMessage(new ChatComponentTranslation("command.skull.feedback", fileName)); - } - - private static final String hex = "0123456789abcdef"; - - public String installNewSkull(byte[] skullData) { - // set to 16384 to save a full 64x64 skin - if(skullData.length > 4096) { - byte[] tmp = skullData; - skullData = new byte[4096]; - System.arraycopy(tmp, 0, skullData, 0, 4096); - } - SHA1Digest sha = new SHA1Digest(); - sha.update(skullData, 0, skullData.length); - byte[] hash = new byte[20]; - sha.doFinal(hash, 0); - char[] hashText = new char[40]; - for(int i = 0; i < 20; ++i) { - hashText[i << 1] = hex.charAt((hash[i] & 0xF0) >> 4); - hashText[(i << 1) + 1] = hex.charAt(hash[i] & 0x0F); - } - String str = "skin-" + new String(hashText) + ".bmp"; - customSkulls.put(str, new CustomSkullData(str, skullData)); - WorldsDB.newVFile(skullsDirectory, str).setAllBytes(skullData); - return str; - } - - private CustomSkullData loadCustomSkull(String urlStr) { - byte[] data = WorldsDB.newVFile(skullsDirectory, urlStr).getAllBytes(); - if(data == null) { - return new CustomSkullData(urlStr, skullNotFoundTexture); - }else { - return new CustomSkullData(urlStr, data); - } - } - - public void flushCache() { - long cur = EagRuntime.steadyTimeMillis(); - if(cur - lastFlush > 300000l) { - lastFlush = cur; - Iterator customSkullsItr = customSkulls.values().iterator(); - while(customSkullsItr.hasNext()) { - if(cur - customSkullsItr.next().lastHit > 900000l) { - customSkullsItr.remove(); - } - } - } - } -} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedTexturePackets.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedTexturePackets.java new file mode 100644 index 00000000..609d78cb --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedTexturePackets.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.sp.server.skins; + +public class IntegratedTexturePackets { + + public static PlayerTextureData handleTextureData(byte[] skinV1, byte[] capeV1) { + int skinId; + byte[] skinTextureDataV3; + eagler: { + if (skinV1 != null && skinV1.length > 0) { + int packetType = (int)skinV1[0] & 0xFF; + switch (packetType) { + case 0x01: + if (skinV1.length == 5) { + skinId = ((skinV1[1] & 0x7F) << 24) | ((skinV1[2] & 0xFF) << 16) + | ((skinV1[3] & 0xFF) << 8) | (skinV1[4] & 0xFF); + skinTextureDataV3 = null; + break eagler; + } + break; + case 0x02: + if (skinV1.length == 16386) { + skinId = -(Math.min((int) skinV1[1] & 0x7F, 0x7E) | 0x80) - 1; + skinTextureDataV3 = new byte[16384]; + System.arraycopy(skinV1, 2, skinTextureDataV3, 0, 16384); + break eagler; + } + break; + default: + break; + } + } + skinId = 0; + skinTextureDataV3 = null; + } + int capeId; + byte[] capeTextureData; + eagler: { + if (capeV1 != null && capeV1.length > 0) { + int packetType = (int)capeV1[0] & 0xFF; + switch (packetType) { + case 0x01: + if(capeV1.length == 5) { + capeId = ((capeV1[1] & 0x7F) << 24) | ((capeV1[2] & 0xFF) << 16) + | ((capeV1[3] & 0xFF) << 8) | (capeV1[4] & 0xFF); + capeTextureData = null; + break eagler; + } + break; + case 0x02: + if (capeV1.length == 1174) { + capeId = -1; + capeTextureData = new byte[1173]; + System.arraycopy(capeV1, 1, capeTextureData, 0, 1173); + break eagler; + } + break; + default: + break; + } + } + capeId = 0; + capeTextureData = null; + } + return new PlayerTextureData(skinId, skinTextureDataV3, null, capeId, capeTextureData); + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedTextureService.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedTextureService.java new file mode 100644 index 00000000..199cd20b --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedTextureService.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.sp.server.skins; + +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.Base64; +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetEAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetV5EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetEAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetV5EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherTexturesV5EAG; +import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerPlayerList; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagString; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; + +public class IntegratedTextureService { + + private final EaglerPlayerList playerList; + private final CustomSkullLoader skullHandler; + + public IntegratedTextureService(EaglerPlayerList playerList, VFile2 file) { + this.playerList = playerList; + this.skullHandler = new CustomSkullLoader(file); + } + + public void handleRequestPlayerSkin(EntityPlayerMP requester, EaglercraftUUID uuid) { + EntityPlayerMP target = playerList.getPlayerByUUID(uuid); + if (target != null && target.textureData != null) { + requester.playerNetServerHandler.sendEaglerMessage(target.textureData.getSkin(uuid.msb, uuid.lsb, + requester.playerNetServerHandler.getEaglerMessageProtocol())); + } else { + requester.playerNetServerHandler.sendEaglerMessage( + new SPacketOtherSkinPresetEAG(uuid.msb, uuid.lsb, (uuid.hashCode() & 1) != 0 ? 1 : 0)); + } + } + + public void handleRequestPlayerCape(EntityPlayerMP requester, EaglercraftUUID uuid) { + EntityPlayerMP target = playerList.getPlayerByUUID(uuid); + if (target != null && target.textureData != null) { + requester.playerNetServerHandler.sendEaglerMessage(target.textureData.getCape(uuid.msb, uuid.lsb, + requester.playerNetServerHandler.getEaglerMessageProtocol())); + } else { + requester.playerNetServerHandler.sendEaglerMessage(new SPacketOtherCapePresetEAG(uuid.msb, uuid.lsb, 0)); + } + } + + public void handleRequestPlayerSkinV5(EntityPlayerMP requester, int requestId, EaglercraftUUID uuid) { + EntityPlayerMP target = playerList.getPlayerByUUID(uuid); + if (target != null && target.textureData != null) { + requester.playerNetServerHandler.sendEaglerMessage(target.textureData.getSkinV5(requestId, + requester.playerNetServerHandler.getEaglerMessageProtocol())); + } else { + requester.playerNetServerHandler.sendEaglerMessage( + new SPacketOtherSkinPresetV5EAG(requestId, (uuid.hashCode() & 1) != 0 ? 1 : 0)); + } + } + + public void handleRequestPlayerCapeV5(EntityPlayerMP requester, int requestId, EaglercraftUUID uuid) { + EntityPlayerMP target = playerList.getPlayerByUUID(uuid); + if (target != null && target.textureData != null) { + requester.playerNetServerHandler.sendEaglerMessage(target.textureData.getCapeV5(requestId, + requester.playerNetServerHandler.getEaglerMessageProtocol())); + } else { + requester.playerNetServerHandler.sendEaglerMessage(new SPacketOtherCapePresetV5EAG(requestId, 0)); + } + } + + public void handleRequestPlayerTexturesV5(EntityPlayerMP requester, int requestId, EaglercraftUUID uuid) { + EntityPlayerMP target = playerList.getPlayerByUUID(uuid); + if (target != null && target.textureData != null) { + requester.playerNetServerHandler.sendEaglerMessage(target.textureData.getTexturesV5(requestId, + requester.playerNetServerHandler.getEaglerMessageProtocol())); + } else { + requester.playerNetServerHandler + .sendEaglerMessage(new SPacketOtherTexturesV5EAG(requestId, 0, null, 0, null)); + } + } + + public void handleRequestSkinByURL(EntityPlayerMP requester, EaglercraftUUID uuid, String url) { + url = url.toLowerCase(); + if (url.startsWith("eagler://")) { + url = url.substring(9); + if (!url.contains(VFile2.pathSeperator)) { + CustomSkullData skull = skullHandler.loadSkullData(url); + if (skull != null) { + requester.playerNetServerHandler.sendEaglerMessage(skull.getSkin(uuid.msb, uuid.lsb, + requester.playerNetServerHandler.getEaglerMessageProtocol())); + return; + } + } + } + requester.playerNetServerHandler.sendEaglerMessage(new SPacketOtherSkinPresetEAG(uuid.msb, uuid.lsb, 0)); + } + + public void handleRequestSkinByURLV5(EntityPlayerMP requester, int requestId, String url) { + url = url.toLowerCase(); + if (url.startsWith("eagler://")) { + url = url.substring(9); + if (!url.contains(VFile2.pathSeperator)) { + CustomSkullData skull = skullHandler.loadSkullData(url); + if (skull != null) { + requester.playerNetServerHandler.sendEaglerMessage(skull.getSkinV5(requestId, + requester.playerNetServerHandler.getEaglerMessageProtocol())); + return; + } + } + } + requester.playerNetServerHandler.sendEaglerMessage(new SPacketOtherSkinPresetV5EAG(requestId, 0)); + } + + public void handleInstallNewSkin(EntityPlayerMP requester, byte[] skullData) { + if (!requester.canCommandSenderUseCommand(2, "give")) { + ChatComponentTranslation cc = new ChatComponentTranslation("command.skull.nopermission"); + cc.getChatStyle().setColor(EnumChatFormatting.RED); + requester.addChatMessage(cc); + return; + } + String fileName = "eagler://" + skullHandler.installNewSkull(skullData); + NBTTagCompound rootTagCompound = new NBTTagCompound(); + NBTTagCompound ownerTagCompound = new NBTTagCompound(); + ownerTagCompound.setString("Name", "Eagler"); + ownerTagCompound.setString("Id", EaglercraftUUID.nameUUIDFromBytes((("EaglerSkullUUID:" + fileName).getBytes(StandardCharsets.UTF_8))).toString()); + NBTTagCompound propertiesTagCompound = new NBTTagCompound(); + NBTTagList texturesTagList = new NBTTagList(); + NBTTagCompound texturesTagCompound = new NBTTagCompound(); + String texturesProp = "{\"textures\":{\"SKIN\":{\"url\":\"" + fileName + "\",\"metadata\":{\"model\":\"default\"}}}}"; + texturesTagCompound.setString("Value", Base64.encodeBase64String(texturesProp.getBytes(StandardCharsets.UTF_8))); + texturesTagList.appendTag(texturesTagCompound); + propertiesTagCompound.setTag("textures", texturesTagList); + ownerTagCompound.setTag("Properties", propertiesTagCompound); + rootTagCompound.setTag("SkullOwner", ownerTagCompound); + NBTTagCompound displayTagCompound = new NBTTagCompound(); + displayTagCompound.setString("Name", EnumChatFormatting.RESET + "Custom Eaglercraft Skull"); + NBTTagList loreList = new NBTTagList(); + loreList.appendTag(new NBTTagString(EnumChatFormatting.GRAY + (fileName.length() > 24 ? (fileName.substring(0, 22) + "...") : fileName))); + displayTagCompound.setTag("Lore", loreList); + rootTagCompound.setTag("display", displayTagCompound); + ItemStack stack = new ItemStack(Items.skull, 1, 3); + stack.setTagCompound(rootTagCompound); + boolean flag = requester.inventory.addItemStackToInventory(stack); + if (flag) { + requester.worldObj.playSoundAtEntity(requester, "random.pop", 0.2F, + ((requester.getRNG().nextFloat() - requester.getRNG().nextFloat()) * 0.7F + 1.0F) + * 2.0F); + requester.inventoryContainer.detectAndSendChanges(); + } + requester.addChatMessage(new ChatComponentTranslation("command.skull.feedback", fileName)); + } + + public void flushCache() { + skullHandler.flushCache(); + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/PlayerTextureData.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/PlayerTextureData.java new file mode 100644 index 00000000..cb130869 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/PlayerTextureData.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.sp.server.skins; + +import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapeCustomEAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapeCustomV5EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetEAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetV5EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV3EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV4EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV5EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetEAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetV5EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherTexturesV5EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache; + +public class PlayerTextureData { + + private int skinId; + private byte[] skinTextureDataV3; + private byte[] skinTextureDataV4; + + private int capeId; + private byte[] capeTextureData; + + public PlayerTextureData(int skinId, byte[] skinTextureDataV3, byte[] skinTextureDataV4, int capeId, + byte[] capeTextureData) { + this.skinId = skinId; + this.skinTextureDataV3 = skinTextureDataV3; + this.skinTextureDataV4 = skinTextureDataV4; + this.capeId = capeId; + this.capeTextureData = capeTextureData; + } + + private byte[] getTextureV3() { + if (skinTextureDataV3 != null) { + return skinTextureDataV3; + } else { + return skinTextureDataV3 = SkinPacketVersionCache.convertToV3Raw(skinTextureDataV4); + } + } + + private byte[] getTextureV4() { + if (skinTextureDataV4 != null) { + return skinTextureDataV4; + } else { + return skinTextureDataV4 = SkinPacketVersionCache.convertToV4Raw(skinTextureDataV3); + } + } + + public GameMessagePacket getSkin(long uuidMost, long uuidLeast, GamePluginMessageProtocol protocol) { + switch(protocol) { + case V3: + if (skinId < 0) { + return new SPacketOtherSkinCustomV3EAG(uuidMost, uuidLeast, -skinId + 1, getTextureV3()); + } else { + return new SPacketOtherSkinPresetEAG(uuidMost, uuidLeast, skinId); + } + case V4: + if (skinId < 0) { + return new SPacketOtherSkinCustomV4EAG(uuidMost, uuidLeast, -skinId + 1, getTextureV4()); + } else { + return new SPacketOtherSkinPresetEAG(uuidMost, uuidLeast, skinId); + } + default: + throw new IllegalStateException(); + } + } + + public GameMessagePacket getSkinV5(int requestId, GamePluginMessageProtocol protocol) { + if(protocol.ver >= 5) { + if (skinId < 0) { + return new SPacketOtherSkinCustomV5EAG(requestId, -skinId + 1, getTextureV4()); + } else { + return new SPacketOtherSkinPresetV5EAG(requestId, skinId); + } + }else { + throw new IllegalStateException(); + } + } + + public GameMessagePacket getCape(long uuidMost, long uuidLeast, GamePluginMessageProtocol protocol) { + if(protocol.ver <= 4) { + if (capeId < 0) { + return new SPacketOtherCapeCustomEAG(uuidMost, uuidLeast, capeTextureData); + } else { + return new SPacketOtherCapePresetEAG(uuidMost, uuidLeast, capeId); + } + }else { + throw new IllegalStateException(); + } + } + + public GameMessagePacket getCapeV5(int requestId, GamePluginMessageProtocol protocol) { + if(protocol.ver >= 5) { + if (capeId < 0) { + return new SPacketOtherCapeCustomV5EAG(requestId, capeTextureData); + } else { + return new SPacketOtherCapePresetV5EAG(requestId, capeId); + } + }else { + throw new IllegalStateException(); + } + } + + public GameMessagePacket getTexturesV5(int requestId, GamePluginMessageProtocol protocol) { + if(protocol.ver >= 5) { + return new SPacketOtherTexturesV5EAG(requestId, skinId, skinId < 0 ? getTextureV4() : null, capeId, + capeId < 0 ? capeTextureData : null); + }else { + throw new IllegalStateException(); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java index 8f308614..d459c778 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -31,6 +31,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; import net.lax1dude.eaglercraft.v1_8.netty.ByteBuf; import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; import net.lax1dude.eaglercraft.v1_8.socket.CompressionNotSupportedException; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.message.InjectedMessageController; import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController; import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker; import net.minecraft.network.EnumConnectionState; @@ -53,6 +54,7 @@ public class IntegratedServerPlayerNetworkManager { private int debugPacketCounter = 0; private final List recievedPacketBuffer = new LinkedList<>(); private final boolean enableSendCompression; + protected InjectedMessageController injectedController = null; private boolean firstPacket = true; @@ -70,6 +72,10 @@ public class IntegratedServerPlayerNetworkManager { this.playerChannel = playerChannel; this.enableSendCompression = !SingleplayerServerController.PLAYER_CHANNEL.equals(playerChannel); } + + public void setInjectedMessageController(InjectedMessageController controller) { + injectedController = controller; + } public void connect() { fragmentedPacket.clear(); @@ -160,6 +166,10 @@ public class IntegratedServerPlayerNetworkManager { ++debugPacketCounter; try { + if(injectedController != null && injectedController.handlePacket(fullData, 0)) { + continue; + } + ByteBuf nettyBuffer = Unpooled.buffer(fullData, fullData.length); nettyBuffer.writerIndex(fullData.length); PacketBuffer input = new PacketBuffer(nettyBuffer); @@ -274,6 +284,66 @@ public class IntegratedServerPlayerNetworkManager { } } + public void injectRawFrame(byte[] data) { + if(!isChannelOpen()) { + return; + } + if(enableSendCompression) { + int len = data.length; + if(len > compressionThreshold) { + if(compressedPacketTmp == null || compressedPacketTmp.length < len) { + compressedPacketTmp = new byte[len]; + } + int cmpLen; + try { + cmpLen = EaglerZLIB.deflateFull(data, 0, len, compressedPacketTmp, 0, compressedPacketTmp.length); + }catch(IOException ex) { + logger.error("Failed to compress injected frame!"); + logger.error(ex); + return; + } + byte[] compressedData = new byte[5 + cmpLen]; + compressedData[0] = (byte)2; + compressedData[1] = (byte)((len >>> 24) & 0xFF); + compressedData[2] = (byte)((len >>> 16) & 0xFF); + compressedData[3] = (byte)((len >>> 8) & 0xFF); + compressedData[4] = (byte)(len & 0xFF); + System.arraycopy(compressedPacketTmp, 0, compressedData, 5, cmpLen); + if(compressedData.length > fragmentSize) { + int fragmentSizeN1 = fragmentSize - 1; + for (int j = 1; j < compressedData.length; j += fragmentSizeN1) { + byte[] fragData = new byte[((j + fragmentSizeN1 > (compressedData.length - 1)) ? ((compressedData.length - 1) % fragmentSizeN1) : fragmentSizeN1) + 1]; + System.arraycopy(compressedData, j, fragData, 1, fragData.length - 1); + fragData[0] = (j + fragmentSizeN1 < compressedData.length) ? (byte) 1 : (byte) 2; + ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, fragData)); + } + }else { + ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, compressedData)); + } + }else { + int fragmentSizeN1 = fragmentSize - 1; + if(len > fragmentSizeN1) { + int idx = 0; + do { + int readLen = len > fragmentSizeN1 ? fragmentSizeN1 : len; + byte[] frag = new byte[readLen + 1]; + System.arraycopy(data, idx, frag, 1, readLen); + idx += readLen; + len -= readLen; + frag[0] = len == 0 ? (byte)0 : (byte)1; + ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, frag)); + }while(len > 0); + }else { + byte[] bytes = new byte[len + 1]; + System.arraycopy(data, 0, bytes, 1, len); + ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, bytes)); + } + } + }else { + ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, data)); + } + } + public void setNetHandler(INetHandler nethandler) { this.nethandler = nethandler; } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerMessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerMessageHandler.java new file mode 100644 index 00000000..3a721a6c --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerMessageHandler.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol; + +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler; +import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer; +import net.minecraft.network.NetHandlerPlayServer; + +public abstract class ServerMessageHandler implements GameMessageHandler { + + protected final NetHandlerPlayServer netHandler; + protected final EaglerMinecraftServer server; + + public ServerMessageHandler(NetHandlerPlayServer netHandler) { + this.netHandler = netHandler; + this.server = (EaglerMinecraftServer)netHandler.serverController; + } + + public static ServerMessageHandler createServerHandler(int version, NetHandlerPlayServer netHandler) { + switch(version) { + case 3: + return new ServerV3MessageHandler(netHandler); + case 4: + return new ServerV4MessageHandler(netHandler); + case 5: + return new ServerV5MessageHandler(netHandler); + default: + throw new UnsupportedOperationException(); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV3MessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV3MessageHandler.java index b3f21e31..64809dd4 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV3MessageHandler.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV3MessageHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -17,58 +17,57 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*; -import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer; import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService; import net.minecraft.network.NetHandlerPlayServer; -public class ServerV3MessageHandler implements GameMessageHandler { - - private final NetHandlerPlayServer netHandler; - private final EaglerMinecraftServer server; +public class ServerV3MessageHandler extends ServerMessageHandler { public ServerV3MessageHandler(NetHandlerPlayServer netHandler) { - this.netHandler = netHandler; - this.server = (EaglerMinecraftServer)netHandler.serverController; + super(netHandler); } public void handleClient(CPacketGetOtherCapeEAG packet) { - server.getCapeService().processGetOtherCape(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity); + server.getTextureService().handleRequestPlayerCape(netHandler.playerEntity, + new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); } public void handleClient(CPacketGetOtherSkinEAG packet) { - server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity); + server.getTextureService().handleRequestPlayerSkin(netHandler.playerEntity, + new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); } public void handleClient(CPacketGetSkinByURLEAG packet) { - server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.url, netHandler.playerEntity); + server.getTextureService().handleRequestSkinByURL(netHandler.playerEntity, + new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.url); } public void handleClient(CPacketInstallSkinSPEAG packet) { - server.getSkinService().processPacketInstallNewSkin(packet.customSkin, netHandler.playerEntity); + server.getTextureService().handleInstallNewSkin(netHandler.playerEntity, packet.customSkin); } public void handleClient(CPacketVoiceSignalConnectEAG packet) { IntegratedVoiceService voiceSvc = server.getVoiceService(); - if(voiceSvc != null) { + if (voiceSvc != null) { voiceSvc.handleVoiceSignalPacketTypeConnect(netHandler.playerEntity); } } public void handleClient(CPacketVoiceSignalDescEAG packet) { IntegratedVoiceService voiceSvc = server.getVoiceService(); - if(voiceSvc != null) { - voiceSvc.handleVoiceSignalPacketTypeDesc(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.desc, netHandler.playerEntity); + if (voiceSvc != null) { + voiceSvc.handleVoiceSignalPacketTypeDesc(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), + packet.desc, netHandler.playerEntity); } } public void handleClient(CPacketVoiceSignalDisconnectV3EAG packet) { IntegratedVoiceService voiceSvc = server.getVoiceService(); - if(voiceSvc != null) { - if(packet.isPeerType) { - voiceSvc.handleVoiceSignalPacketTypeDisconnectPeer(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity); - }else { + if (voiceSvc != null) { + if (packet.isPeerType) { + voiceSvc.handleVoiceSignalPacketTypeDisconnectPeer( + new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity); + } else { voiceSvc.handleVoiceSignalPacketTypeDisconnect(netHandler.playerEntity); } } @@ -76,15 +75,17 @@ public class ServerV3MessageHandler implements GameMessageHandler { public void handleClient(CPacketVoiceSignalICEEAG packet) { IntegratedVoiceService voiceSvc = server.getVoiceService(); - if(voiceSvc != null) { - voiceSvc.handleVoiceSignalPacketTypeICE(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.ice, netHandler.playerEntity); + if (voiceSvc != null) { + voiceSvc.handleVoiceSignalPacketTypeICE(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.ice, + netHandler.playerEntity); } } public void handleClient(CPacketVoiceSignalRequestEAG packet) { IntegratedVoiceService voiceSvc = server.getVoiceService(); - if(voiceSvc != null) { - voiceSvc.handleVoiceSignalPacketTypeRequest(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity); + if (voiceSvc != null) { + voiceSvc.handleVoiceSignalPacketTypeRequest(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), + netHandler.playerEntity); } } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV4MessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV4MessageHandler.java index 903a269b..9dfd69d6 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV4MessageHandler.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV4MessageHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -17,52 +17,21 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.WrongPacketException; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherPlayerClientUUIDV4EAG; -import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer; import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.network.NetHandlerPlayServer; -public class ServerV4MessageHandler implements GameMessageHandler { - - private final NetHandlerPlayServer netHandler; - private final EaglerMinecraftServer server; +public class ServerV4MessageHandler extends ServerV3MessageHandler { public ServerV4MessageHandler(NetHandlerPlayServer netHandler) { - this.netHandler = netHandler; - this.server = (EaglerMinecraftServer)netHandler.serverController; + super(netHandler); } - public void handleClient(CPacketGetOtherCapeEAG packet) { - server.getCapeService().processGetOtherCape(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity); - } - - public void handleClient(CPacketGetOtherSkinEAG packet) { - server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity); - } - - public void handleClient(CPacketGetSkinByURLEAG packet) { - server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.url, netHandler.playerEntity); - } - - public void handleClient(CPacketInstallSkinSPEAG packet) { - server.getSkinService().processPacketInstallNewSkin(packet.customSkin, netHandler.playerEntity); - } - - public void handleClient(CPacketVoiceSignalConnectEAG packet) { - IntegratedVoiceService voiceSvc = server.getVoiceService(); - if(voiceSvc != null) { - voiceSvc.handleVoiceSignalPacketTypeConnect(netHandler.playerEntity); - } - } - - public void handleClient(CPacketVoiceSignalDescEAG packet) { - IntegratedVoiceService voiceSvc = server.getVoiceService(); - if(voiceSvc != null) { - voiceSvc.handleVoiceSignalPacketTypeDesc(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.desc, netHandler.playerEntity); - } + public void handleClient(CPacketVoiceSignalDisconnectV3EAG packet) { + throw new WrongPacketException(); } public void handleClient(CPacketVoiceSignalDisconnectV4EAG packet) { @@ -74,30 +43,19 @@ public class ServerV4MessageHandler implements GameMessageHandler { public void handleClient(CPacketVoiceSignalDisconnectPeerV4EAG packet) { IntegratedVoiceService voiceSvc = server.getVoiceService(); - if(voiceSvc != null) { - voiceSvc.handleVoiceSignalPacketTypeDisconnectPeer(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity); - } - } - - public void handleClient(CPacketVoiceSignalICEEAG packet) { - IntegratedVoiceService voiceSvc = server.getVoiceService(); - if(voiceSvc != null) { - voiceSvc.handleVoiceSignalPacketTypeICE(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.ice, netHandler.playerEntity); - } - } - - public void handleClient(CPacketVoiceSignalRequestEAG packet) { - IntegratedVoiceService voiceSvc = server.getVoiceService(); - if(voiceSvc != null) { - voiceSvc.handleVoiceSignalPacketTypeRequest(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity); + if (voiceSvc != null) { + voiceSvc.handleVoiceSignalPacketTypeDisconnectPeer(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), + netHandler.playerEntity); } } public void handleClient(CPacketGetOtherClientUUIDV4EAG packet) { - EntityPlayerMP player = server.getConfigurationManager().getPlayerByUUID(new EaglercraftUUID(packet.playerUUIDMost, packet.playerUUIDLeast)); - if(player != null && player.clientBrandUUID != null) { - netHandler.sendEaglerMessage(new SPacketOtherPlayerClientUUIDV4EAG(packet.requestId, player.clientBrandUUID.msb, player.clientBrandUUID.lsb)); - }else { + EntityPlayerMP player = server.getConfigurationManager() + .getPlayerByUUID(new EaglercraftUUID(packet.playerUUIDMost, packet.playerUUIDLeast)); + if (player != null && player.clientBrandUUID != null) { + netHandler.sendEaglerMessage(new SPacketOtherPlayerClientUUIDV4EAG(packet.requestId, + player.clientBrandUUID.msb, player.clientBrandUUID.lsb)); + } else { netHandler.sendEaglerMessage(new SPacketOtherPlayerClientUUIDV4EAG(packet.requestId, 0l, 0l)); } } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV5MessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV5MessageHandler.java new file mode 100644 index 00000000..a1131424 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV5MessageHandler.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol; + +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.WrongPacketException; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*; +import net.minecraft.network.NetHandlerPlayServer; + +public class ServerV5MessageHandler extends ServerV4MessageHandler { + + public ServerV5MessageHandler(NetHandlerPlayServer netHandler) { + super(netHandler); + } + + public void handleClient(CPacketGetOtherCapeEAG packet) { + throw new WrongPacketException(); + } + + public void handleClient(CPacketGetOtherSkinEAG packet) { + throw new WrongPacketException(); + } + + public void handleClient(CPacketGetSkinByURLEAG packet) { + throw new WrongPacketException(); + } + + public void handleClient(CPacketGetOtherCapeV5EAG packet) { + server.getTextureService().handleRequestPlayerCapeV5(netHandler.playerEntity, packet.requestId, + new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); + } + + public void handleClient(CPacketGetOtherSkinV5EAG packet) { + server.getTextureService().handleRequestPlayerSkinV5(netHandler.playerEntity, packet.requestId, + new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); + } + + public void handleClient(CPacketGetSkinByURLV5EAG packet) { + server.getTextureService().handleRequestSkinByURLV5(netHandler.playerEntity, packet.requestId, packet.url); + } + + public void handleClient(CPacketGetOtherTexturesV5EAG packet) { + server.getTextureService().handleRequestPlayerTexturesV5(netHandler.playerEntity, packet.requestId, + new EaglercraftUUID(packet.uuidMost, packet.uuidLeast)); + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceService.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceService.java index 5deaea61..63122e33 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceService.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceService.java @@ -32,6 +32,7 @@ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*; import net.lax1dude.eaglercraft.v1_8.voice.ExpiringSet; import net.minecraft.entity.player.EntityPlayerMP; +//TODO: Rewrite to be more like EaglerXServer public class IntegratedVoiceService { public static final Logger logger = LogManager.getLogger("IntegratedVoiceService"); @@ -151,22 +152,33 @@ public class IntegratedVoiceService { } GameMessagePacket v3p = null; GameMessagePacket v4p = null; - for(EntityPlayerMP conn : voicePlayers.values()) { - if(conn.playerNetServerHandler.getEaglerMessageProtocol().ver <= 3) { - conn.playerNetServerHandler.sendEaglerMessage(v3p == null ? (v3p = new SPacketVoiceSignalConnectV3EAG(senderUuid.msb, senderUuid.lsb, true, false)) : v3p); - } else { - conn.playerNetServerHandler.sendEaglerMessage(v4p == null ? (v4p = new SPacketVoiceSignalConnectAnnounceV4EAG(senderUuid.msb, senderUuid.lsb)) : v4p); - } - } Collection userDatas = new ArrayList<>(voicePlayers.size()); - for(EntityPlayerMP player : voicePlayers.values()) { - EaglercraftUUID uuid = player.getUniqueID(); - userDatas.add(new SPacketVoiceSignalGlobalEAG.UserData(uuid.msb, uuid.lsb, player.getName())); + for(EntityPlayerMP conn : voicePlayers.values()) { + EaglercraftUUID otherUuid = conn.getUniqueID(); + if(conn != sender) { + if(conn.playerNetServerHandler.getEaglerMessageProtocol().ver <= 3) { + conn.playerNetServerHandler.sendEaglerMessage(v3p == null ? (v3p = new SPacketVoiceSignalConnectV3EAG(senderUuid.msb, senderUuid.lsb, true, false)) : v3p); + } else { + conn.playerNetServerHandler.sendEaglerMessage(v4p == null ? (v4p = new SPacketVoiceSignalConnectAnnounceV4EAG(senderUuid.msb, senderUuid.lsb)) : v4p); + } + } + userDatas.add(new SPacketVoiceSignalGlobalEAG.UserData(otherUuid.msb, otherUuid.lsb, conn.getName())); } SPacketVoiceSignalGlobalEAG packetToBroadcast = new SPacketVoiceSignalGlobalEAG(userDatas); for (EntityPlayerMP userCon : voicePlayers.values()) { userCon.playerNetServerHandler.sendEaglerMessage(packetToBroadcast); } + boolean selfV3 = sender.playerNetServerHandler.getEaglerMessageProtocol().ver <= 3; + for(EntityPlayerMP conn : voicePlayers.values()) { + EaglercraftUUID otherUuid = conn.getUniqueID(); + if(conn != sender) { + if(selfV3) { + sender.playerNetServerHandler.sendEaglerMessage(new SPacketVoiceSignalConnectV3EAG(otherUuid.msb, otherUuid.lsb, true, false)); + }else { + sender.playerNetServerHandler.sendEaglerMessage(new SPacketVoiceSignalConnectAnnounceV4EAG(otherUuid.msb, otherUuid.lsb)); + } + } + } } public void handleVoiceSignalPacketTypeICE(EaglercraftUUID player, byte[] str, EntityPlayerMP sender) { diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java index d4316219..d0401535 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024 lax1dude, ayunami2000. All Rights Reserved. + * Copyright (c) 2023-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -78,6 +78,10 @@ public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkMana byte[] next = recievedPacketBuffer.remove(0); ++debugPacketCounter; try { + if(injectedController != null && injectedController.handlePacket(next, 0)) { + continue; + } + ByteBuf nettyBuffer = Unpooled.buffer(next, next.length); nettyBuffer.writerIndex(next.length); PacketBuffer input = new PacketBuffer(nettyBuffer); @@ -168,4 +172,14 @@ public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkMana public void clearRecieveQueue() { recievedPacketBuffer.clear(); } + + @Override + public void injectRawFrame(byte[] data) { + if(!isChannelOpen()) { + logger.error("Frame was injected on a closed connection"); + return; + } + ClientPlatformSingleplayer.sendPacket(new IPCPacketData(address, data)); + } + } \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/NetHandlerSingleplayerLogin.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/NetHandlerSingleplayerLogin.java index a5d2650e..1622625e 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/NetHandlerSingleplayerLogin.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/NetHandlerSingleplayerLogin.java @@ -20,9 +20,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants; import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController; import net.lax1dude.eaglercraft.v1_8.update.UpdateService; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiDisconnected; @@ -73,15 +71,14 @@ public class NetHandlerSingleplayerLogin implements INetHandlerLoginClient { return; } logger.info("Server is using protocol: {}", p); - NetHandlerPlayClient netHandler = new NetHandlerPlayClient(this.mc, this.previousGuiScreen, this.networkManager, var1.getProfile()); - netHandler.setEaglerMessageController( - new GameProtocolMessageController(mp, GamePluginMessageConstants.CLIENT_TO_SERVER, - GameProtocolMessageController.createClientHandler(p, netHandler), - (ch, msg) -> netHandler.addToSendQueue(new C17PacketCustomPayload(ch, msg)))); + this.networkManager.setLANInfo(p); + NetHandlerPlayClient netHandler = new NetHandlerPlayClient(this.mc, this.previousGuiScreen, this.networkManager, + var1.getProfile(), mp); this.networkManager.setNetHandler(netHandler); byte[] b = UpdateService.getClientSignatureData(); if(b != null) { - this.networkManager.sendPacket(new C17PacketCustomPayload("EAG|MyUpdCert-1.8", new PacketBuffer(Unpooled.buffer(b, b.length).writerIndex(b.length)))); + this.networkManager.sendPacket(new C17PacketCustomPayload("EAG|MyUpdCert-1.8", + new PacketBuffer(Unpooled.buffer(b, b.length).writerIndex(b.length)))); } } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientController.java index 01175495..e2b26ce8 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientController.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -18,13 +18,10 @@ package net.lax1dude.eaglercraft.v1_8.voice; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.function.Consumer; -import java.util.stream.Collectors; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; @@ -32,32 +29,21 @@ import net.lax1dude.eaglercraft.v1_8.Keyboard; import net.lax1dude.eaglercraft.v1_8.internal.PlatformVoiceClient; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; -import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; -import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketVoiceSignalGlobalEAG; -import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController; import net.minecraft.client.Minecraft; -import net.minecraft.entity.player.EntityPlayer; public class VoiceClientController { - public static final String SIGNAL_CHANNEL = "EAG|Voice-1.8"; - static final Logger logger = LogManager.getLogger("VoiceClientController"); private static boolean clientSupport = false; private static boolean serverSupport = false; private static Consumer packetSendCallback = null; private static int protocolVersion = -1; - private static EnumVoiceChannelType voiceChannel = EnumVoiceChannelType.NONE; - private static final HashSet nearbyPlayers = new HashSet<>(); - private static final ExpiringSet recentlyNearbyPlayers = new ExpiringSet<>(5000, uuid -> { - if (!nearbyPlayers.contains(uuid)) { - PlatformVoiceClient.signalDisconnect(uuid, false); - } - }); - private static final Map uuidToNameLookup = new HashMap<>(256); + private static VoiceClientInstance voiceClient = null; + + static EnumVoiceChannelType lastVoiceChannel = EnumVoiceChannelType.NONE; public static boolean isSupported() { return isClientSupported() && isServerSupported(); @@ -78,202 +64,118 @@ public class VoiceClientController { } public static void initializeVoiceClient(Consumer signalSendCallbackIn, int proto) { + if (!isClientSupported()) return; packetSendCallback = signalSendCallbackIn; protocolVersion = proto; - uuidToNameLookup.clear(); - if (getVoiceChannel() != EnumVoiceChannelType.NONE) sendInitialVoice(); - } - - public static void handleVoiceSignalPacketTypeGlobal(EaglercraftUUID[] voicePlayers, String[] voiceNames) { - uuidToNameLookup.clear(); - for (int i = 0; i < voicePlayers.length; i++) { - if(voiceNames != null) { - uuidToNameLookup.put(voicePlayers[i], voiceNames[i]); - } - sendPacketRequestIfNeeded(voicePlayers[i]); + handleRelease(); + if (signalSendCallbackIn != null && serverSupport) { + voiceClient = new VoiceClientInstance(proto, signalSendCallbackIn); + voiceClient.initialize(lastVoiceChannel); } } + private static void handleRelease() { + if (voiceClient != null) { + voiceClient.release(); + voiceClient = null; + } + speakingSet.clear(); + activateVoice(false); + } + public static void handleVoiceSignalPacketTypeGlobalNew(Collection voicePlayers) { - boolean isGlobal = voiceChannel == EnumVoiceChannelType.GLOBAL; - uuidToNameLookup.clear(); - for (SPacketVoiceSignalGlobalEAG.UserData player : voicePlayers) { - EaglercraftUUID uuid = new EaglercraftUUID(player.uuidMost, player.uuidLeast); - if(player.username != null) { - uuidToNameLookup.put(uuid, player.username); - } - if (isGlobal) { - sendPacketRequestIfNeeded(uuid); - } + if (voiceClient != null) { + voiceClient.handleVoiceSignalPacketTypeGlobal(voicePlayers); } } public static void handleServerDisconnect() { - if(!isClientSupported()) return; + if (!isClientSupported()) return; serverSupport = false; - uuidToNameLookup.clear(); - for (EaglercraftUUID uuid : nearbyPlayers) { - PlatformVoiceClient.signalDisconnect(uuid, false); - } - for (EaglercraftUUID uuid : recentlyNearbyPlayers) { - PlatformVoiceClient.signalDisconnect(uuid, false); - } - nearbyPlayers.clear(); - recentlyNearbyPlayers.clear(); - Set antiConcurrentModificationUUIDs = new HashSet<>(listeningSet); - for (EaglercraftUUID uuid : antiConcurrentModificationUUIDs) { - PlatformVoiceClient.signalDisconnect(uuid, false); - } - activateVoice(false); + packetSendCallback = null; + protocolVersion = -1; + handleRelease(); } public static void handleVoiceSignalPacketTypeAllowed(boolean voiceAvailableStat, String[] servs) { - serverSupport = voiceAvailableStat; - PlatformVoiceClient.setICEServers(servs); - if(isSupported()) { - EnumVoiceChannelType ch = getVoiceChannel(); - setVoiceChannel(EnumVoiceChannelType.NONE); - setVoiceChannel(ch); + if(packetSendCallback != null) { + handleRelease(); + PlatformVoiceClient.setICEServers(servs); + if (serverSupport != voiceAvailableStat) { + serverSupport = voiceAvailableStat; + if (voiceAvailableStat) { + voiceClient = new VoiceClientInstance(protocolVersion, packetSendCallback); + voiceClient.initialize(lastVoiceChannel); + } + } } } public static void handleVoiceSignalPacketTypeConnect(EaglercraftUUID user, boolean offer) { - if (voiceChannel != EnumVoiceChannelType.NONE) PlatformVoiceClient.signalConnect(user, offer); + if (voiceClient != null) { + voiceClient.handleVoiceSignalPacketTypeConnect(user, offer); + } } public static void handleVoiceSignalPacketTypeConnectAnnounce(EaglercraftUUID user) { - if (voiceChannel != EnumVoiceChannelType.NONE && (voiceChannel == EnumVoiceChannelType.GLOBAL || listeningSet.contains(user))) sendPacketRequest(user); + if (voiceClient != null) { + voiceClient.handleVoiceSignalPacketTypeConnectAnnounce(user); + } } public static void handleVoiceSignalPacketTypeDisconnect(EaglercraftUUID user) { - if (voiceChannel != EnumVoiceChannelType.NONE) PlatformVoiceClient.signalDisconnect(user, true); + if (voiceClient != null) { + voiceClient.handleVoiceSignalPacketTypeDisconnect(user); + } } public static void handleVoiceSignalPacketTypeICECandidate(EaglercraftUUID user, String ice) { - if (voiceChannel != EnumVoiceChannelType.NONE) PlatformVoiceClient.signalICECandidate(user, ice); + if (voiceClient != null) { + voiceClient.handleVoiceSignalPacketTypeICECandidate(user, ice); + } } public static void handleVoiceSignalPacketTypeDescription(EaglercraftUUID user, String desc) { - if (voiceChannel != EnumVoiceChannelType.NONE) PlatformVoiceClient.signalDescription(user, desc); + if (voiceClient != null) { + voiceClient.handleVoiceSignalPacketTypeDescription(user, desc); + } } - public static void tickVoiceClient(Minecraft mc) { - if(!isClientSupported()) return; - recentlyNearbyPlayers.checkForExpirations(); - speakingSet.clear(); - PlatformVoiceClient.tickVoiceClient(); - - if (getVoiceChannel() != EnumVoiceChannelType.NONE && (getVoiceStatus() == EnumVoiceChannelStatus.CONNECTING || getVoiceStatus() == EnumVoiceChannelStatus.CONNECTED)) { - activateVoice((mc.currentScreen == null || !mc.currentScreen.blockPTTKey()) && Keyboard.isKeyDown(mc.gameSettings.voicePTTKey)); - - if(mc.isSingleplayer() && !LANServerController.isHostingLAN()) { - setVoiceChannel(EnumVoiceChannelType.NONE); - return; - } - - if (mc.theWorld != null && mc.thePlayer != null) { - HashSet seenPlayers = new HashSet<>(); - for (EntityPlayer player : mc.theWorld.playerEntities) { - if (player == mc.thePlayer) continue; - if (getVoiceChannel() == EnumVoiceChannelType.PROXIMITY) updateVoicePosition(player.getUniqueID(), player.posX, player.posY + player.getEyeHeight(), player.posZ); - int prox = 22; - // cube - if (Math.abs(mc.thePlayer.posX - player.posX) <= prox && Math.abs(mc.thePlayer.posY - player.posY) <= prox && Math.abs(mc.thePlayer.posZ - player.posZ) <= prox) { - if (!uuidToNameLookup.containsKey(player.getUniqueID())) { - uuidToNameLookup.put(player.getUniqueID(), player.getName()); - } - if (addNearbyPlayer(player.getUniqueID())) { - seenPlayers.add(player.getUniqueID()); - } - } - } - cleanupNearbyPlayers(seenPlayers); + public static void tickVoiceClient() { + if (voiceClient != null) { + voiceClient.tickVoiceClient(); + Minecraft mc = Minecraft.getMinecraft(); + if (voiceClient.getVoiceChannel() != EnumVoiceChannelType.NONE) { + activateVoice((mc.currentScreen == null || !mc.currentScreen.blockPTTKey()) + && Keyboard.isKeyDown(mc.gameSettings.voicePTTKey)); + } else { + activateVoice(false); } + speakingSet.clear(); + PlatformVoiceClient.tickVoiceClient(); } } - public static final boolean addNearbyPlayer(EaglercraftUUID uuid) { - recentlyNearbyPlayers.remove(uuid); - if (nearbyPlayers.add(uuid)) { - sendPacketRequestIfNeeded(uuid); - return true; - } - return false; - } - - public static final void removeNearbyPlayer(EaglercraftUUID uuid) { - if (nearbyPlayers.remove(uuid)) { - if (getVoiceStatus() == EnumVoiceChannelStatus.DISCONNECTED || getVoiceStatus() == EnumVoiceChannelStatus.UNAVAILABLE) return; - if (voiceChannel == EnumVoiceChannelType.PROXIMITY) recentlyNearbyPlayers.add(uuid); - } - } - - public static final void cleanupNearbyPlayers(HashSet existingPlayers) { - nearbyPlayers.stream().filter(ud -> !existingPlayers.contains(ud)).collect(Collectors.toSet()).forEach(VoiceClientController::removeNearbyPlayer); - } - - public static final void updateVoicePosition(EaglercraftUUID uuid, double x, double y, double z) { - PlatformVoiceClient.updateVoicePosition(uuid, x, y, z); - } - public static void setVoiceChannel(EnumVoiceChannelType channel) { - if (voiceChannel == channel) return; - if (channel != EnumVoiceChannelType.NONE) PlatformVoiceClient.initializeDevices(); - if (channel == EnumVoiceChannelType.NONE) { - for (EaglercraftUUID uuid : nearbyPlayers) { - PlatformVoiceClient.signalDisconnect(uuid, false); - } - for (EaglercraftUUID uuid : recentlyNearbyPlayers) { - PlatformVoiceClient.signalDisconnect(uuid, false); - } - nearbyPlayers.clear(); - recentlyNearbyPlayers.clear(); - Set antiConcurrentModificationUUIDs = new HashSet<>(listeningSet); - for (EaglercraftUUID uuid : antiConcurrentModificationUUIDs) { - PlatformVoiceClient.signalDisconnect(uuid, false); - } - sendPacketDisconnect(); - activateVoice(false); - } else if (voiceChannel == EnumVoiceChannelType.PROXIMITY) { - for (EaglercraftUUID uuid : nearbyPlayers) { - PlatformVoiceClient.signalDisconnect(uuid, false); - } - for (EaglercraftUUID uuid : recentlyNearbyPlayers) { - PlatformVoiceClient.signalDisconnect(uuid, false); - } - nearbyPlayers.clear(); - recentlyNearbyPlayers.clear(); - sendPacketDisconnect(); - } else if(voiceChannel == EnumVoiceChannelType.GLOBAL) { - Set antiConcurrentModificationUUIDs = new HashSet<>(listeningSet); - antiConcurrentModificationUUIDs.removeAll(nearbyPlayers); - antiConcurrentModificationUUIDs.removeAll(recentlyNearbyPlayers); - for (EaglercraftUUID uuid : antiConcurrentModificationUUIDs) { - PlatformVoiceClient.signalDisconnect(uuid, false); - } - sendPacketDisconnect(); - } - voiceChannel = channel; - if (channel != EnumVoiceChannelType.NONE) { - sendInitialVoice(); - } - } - - public static void sendInitialVoice() { - sendPacketConnect(); - for (EaglercraftUUID uuid : nearbyPlayers) { - sendPacketRequest(uuid); + if (voiceClient != null) { + voiceClient.setVoiceChannel(channel); } } public static EnumVoiceChannelType getVoiceChannel() { - return voiceChannel; + if (voiceClient != null) { + return voiceClient.getVoiceChannel(); + } else { + return EnumVoiceChannelType.NONE; + } } public static EnumVoiceChannelStatus getVoiceStatus() { - return (!isClientSupported() || !isServerSupported()) ? EnumVoiceChannelStatus.UNAVAILABLE : - (PlatformVoiceClient.getReadyState() != EnumVoiceChannelReadyState.DEVICE_INITIALIZED ? - EnumVoiceChannelStatus.CONNECTING : EnumVoiceChannelStatus.CONNECTED); + if (voiceClient != null) { + return voiceClient.getVoiceStatus(); + } else { + return EnumVoiceChannelStatus.UNAVAILABLE; + } } private static boolean talkStatus = false; @@ -350,60 +252,29 @@ public class VoiceClientController { } public static String getVoiceUsername(EaglercraftUUID uuid) { - if(uuid == null) { - return "null"; + if (voiceClient != null) { + return voiceClient.getVoiceUsername(uuid); + } else { + return uuid.toString(); } - String ret = uuidToNameLookup.get(uuid); - return ret == null ? uuid.toString() : ret; } public static void sendPacketICE(EaglercraftUUID peerId, String candidate) { - if(packetSendCallback != null) { - packetSendCallback.accept(new CPacketVoiceSignalICEEAG(peerId.msb, peerId.lsb, candidate)); + if (voiceClient != null) { + voiceClient.sendPacketICE(peerId, candidate); } } public static void sendPacketDesc(EaglercraftUUID peerId, String desc) { - if(packetSendCallback != null) { - packetSendCallback.accept(new CPacketVoiceSignalDescEAG(peerId.msb, peerId.lsb, desc)); - } - } - - public static void sendPacketDisconnect() { - if(packetSendCallback != null) { - if(protocolVersion <= 3) { - packetSendCallback.accept(new CPacketVoiceSignalDisconnectV3EAG()); - }else { - packetSendCallback.accept(new CPacketVoiceSignalDisconnectV4EAG()); - } + if (voiceClient != null) { + voiceClient.sendPacketDesc(peerId, desc); } } public static void sendPacketDisconnectPeer(EaglercraftUUID peerId) { - if(packetSendCallback != null) { - if(protocolVersion <= 3) { - packetSendCallback.accept(new CPacketVoiceSignalDisconnectV3EAG(true, peerId.msb, peerId.lsb)); - }else { - packetSendCallback.accept(new CPacketVoiceSignalDisconnectPeerV4EAG(peerId.msb, peerId.lsb)); - } + if (voiceClient != null) { + voiceClient.sendPacketDisconnectPeer(peerId); } } - public static void sendPacketConnect() { - if(packetSendCallback != null) { - packetSendCallback.accept(new CPacketVoiceSignalConnectEAG()); - } - } - - public static void sendPacketRequest(EaglercraftUUID peerId) { - if(packetSendCallback != null) { - packetSendCallback.accept(new CPacketVoiceSignalRequestEAG(peerId.msb, peerId.lsb)); - } - } - - private static void sendPacketRequestIfNeeded(EaglercraftUUID uuid) { - if (getVoiceStatus() == EnumVoiceChannelStatus.DISCONNECTED || getVoiceStatus() == EnumVoiceChannelStatus.UNAVAILABLE) return; - if(uuid.equals(EaglerProfile.getPlayerUUID())) return; - if (!getVoiceListening().contains(uuid)) sendPacketRequest(uuid); - } } \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientInstance.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientInstance.java new file mode 100644 index 00000000..06e86d44 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientInstance.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2025 lax1dude, ayunami2000. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.voice; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +import net.lax1dude.eaglercraft.v1_8.EagRuntime; +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import net.lax1dude.eaglercraft.v1_8.internal.PlatformVoiceClient; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketVoiceSignalConnectEAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketVoiceSignalDescEAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketVoiceSignalDisconnectPeerV4EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketVoiceSignalDisconnectV3EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketVoiceSignalDisconnectV4EAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketVoiceSignalICEEAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketVoiceSignalRequestEAG; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketVoiceSignalGlobalEAG; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; + +public class VoiceClientInstance { + + private final int protocolVers; + private final Consumer packetSendCallback; + private final Map voicePlayers = new HashMap<>(32); + private EnumVoiceChannelType voiceChannel = EnumVoiceChannelType.NONE; + private long lastUpdate = 0l; + + protected VoiceClientInstance(int protocolVers, Consumer packetSendCallback) { + this.protocolVers = protocolVers; + this.packetSendCallback = packetSendCallback; + } + + public void initialize(EnumVoiceChannelType voiceChannel) { + setVoiceChannel(voiceChannel); + } + + public EnumVoiceChannelType getVoiceChannel() { + return voiceChannel; + } + + public void setVoiceChannel(EnumVoiceChannelType channel) { + VoiceClientController.lastVoiceChannel = channel; + if (voiceChannel == channel) return; + if (channel != EnumVoiceChannelType.NONE) { + PlatformVoiceClient.initializeDevices(); + } + if (channel == EnumVoiceChannelType.NONE) { + release(); + packetSendCallback.accept(new CPacketVoiceSignalDisconnectV4EAG()); + } else { + if (voiceChannel == EnumVoiceChannelType.PROXIMITY && channel == EnumVoiceChannelType.GLOBAL) { + for (VoicePlayerState state : voicePlayers.values()) { + if(!state.nearby) { + state.tryRequest(EagRuntime.steadyTimeMillis()); + } + PlatformVoiceClient.makePeerGlobal(state.uuid); + } + } else if (voiceChannel == EnumVoiceChannelType.GLOBAL && channel == EnumVoiceChannelType.PROXIMITY) { + for (VoicePlayerState state : new ArrayList<>(voicePlayers.values())) { + recheckNearby(state); + if(!state.nearby) { + PlatformVoiceClient.signalDisconnect(state.uuid, false); + } + PlatformVoiceClient.makePeerProximity(state.uuid); + } + } else if (voiceChannel == EnumVoiceChannelType.NONE) { + packetSendCallback.accept(new CPacketVoiceSignalConnectEAG()); + } + } + voiceChannel = channel; + } + + public void handleVoiceSignalPacketTypeGlobal(Collection voicePlayers) { + if (voiceChannel != EnumVoiceChannelType.NONE) { + EaglercraftUUID self = Minecraft.getMinecraft().getSession().getProfile().getId(); + Set playersLost = new HashSet<>(this.voicePlayers.keySet()); + for (SPacketVoiceSignalGlobalEAG.UserData userData : voicePlayers) { + EaglercraftUUID uuid = new EaglercraftUUID(userData.uuidMost, userData.uuidLeast); + if (!uuid.equals(self)) { + if (!playersLost.remove(uuid)) { + announcePlayer(uuid); + } + this.voicePlayers.get(uuid).name = userData.username; + } + } + if (!playersLost.isEmpty()) { + for (EaglercraftUUID uuid : playersLost) { + dropPlayer(uuid); + } + } + } + } + + private void announcePlayer(EaglercraftUUID uuid) { + VoicePlayerState voiceState = new VoicePlayerState(this, uuid); + voicePlayers.put(uuid, voiceState); + if (voiceChannel == EnumVoiceChannelType.GLOBAL) { + voiceState.tryRequest(EagRuntime.steadyTimeMillis()); + } else if (voiceChannel == EnumVoiceChannelType.PROXIMITY) { + recheckNearby(voiceState); + if(voiceState.nearby) { + voiceState.tryRequest(EagRuntime.steadyTimeMillis()); + } + } + } + + private void recheckNearby(VoicePlayerState voiceState) { + Minecraft mc = Minecraft.getMinecraft(); + if(mc.theWorld != null) { + EntityPlayer player = mc.theWorld.getPlayerEntityByUUID(voiceState.uuid); + if(player != null) { + voiceState.nearby = goddamnManhattanDistance(mc, player); + if(voiceState.nearby) { + PlatformVoiceClient.updateVoicePosition(voiceState.uuid, player.posX, player.posY, player.posZ); + } + return; + } + } + voiceState.nearby = false; + } + + // Must perform these ham-fisted manhattan distance calculations to work with old clients + private boolean goddamnManhattanDistance(Minecraft mc, Entity player) { + final int prox = 22; + return Math.abs(mc.thePlayer.posX - player.posX) <= prox && Math.abs(mc.thePlayer.posY - player.posY) <= prox + && Math.abs(mc.thePlayer.posZ - player.posZ) <= prox; + } + + private void dropPlayer(EaglercraftUUID uuid) { + voicePlayers.remove(uuid); + PlatformVoiceClient.signalDisconnect(uuid, true); + } + + public void handleVoiceSignalPacketTypeConnectAnnounce(EaglercraftUUID user) { + if (voiceChannel != EnumVoiceChannelType.NONE) { + if (!voicePlayers.containsKey(user)) { + // Backwards compat with old servers :( + announcePlayer(user); + } + } + } + + public void handleVoiceSignalPacketTypeConnect(EaglercraftUUID user, boolean offer) { + if (voiceChannel != EnumVoiceChannelType.NONE) { + PlatformVoiceClient.signalConnect(user, offer); + } + } + + public void handleVoiceSignalPacketTypeICECandidate(EaglercraftUUID user, String ice) { + if (voiceChannel != EnumVoiceChannelType.NONE) { + PlatformVoiceClient.signalICECandidate(user, ice); + } + } + + public void handleVoiceSignalPacketTypeDescription(EaglercraftUUID user, String desc) { + if (voiceChannel != EnumVoiceChannelType.NONE) { + PlatformVoiceClient.signalDescription(user, desc); + } + } + + public void handleVoiceSignalPacketTypeDisconnect(EaglercraftUUID user) { + if (voiceChannel != EnumVoiceChannelType.NONE) { + VoicePlayerState state = voicePlayers.get(user); + if (state != null) { + state.handleDisconnect(); + } + PlatformVoiceClient.signalDisconnect(user, true); + } + } + + public void sendPacketRequest(VoicePlayerState voicePlayerState) { + if (voiceChannel != EnumVoiceChannelType.NONE) { + packetSendCallback.accept(new CPacketVoiceSignalRequestEAG(voicePlayerState.uuid.msb, voicePlayerState.uuid.lsb)); + } + } + + public void sendPacketDesc(EaglercraftUUID peerId, String desc) { + if (voiceChannel != EnumVoiceChannelType.NONE) { + packetSendCallback.accept(new CPacketVoiceSignalDescEAG(peerId.msb, peerId.lsb, desc)); + } + } + + public void sendPacketICE(EaglercraftUUID peerId, String candidate) { + if (voiceChannel != EnumVoiceChannelType.NONE) { + packetSendCallback.accept(new CPacketVoiceSignalICEEAG(peerId.msb, peerId.lsb, candidate)); + } + } + + public void sendPacketDisconnectPeer(EaglercraftUUID peerId) { + if (voiceChannel != EnumVoiceChannelType.NONE) { + VoicePlayerState state = voicePlayers.get(peerId); + if (state != null) { + state.handleDisconnect(); + } + if (protocolVers >= 4) { + packetSendCallback.accept(new CPacketVoiceSignalDisconnectPeerV4EAG(peerId.msb, peerId.lsb)); + } else { + packetSendCallback.accept(new CPacketVoiceSignalDisconnectV3EAG(true, peerId.msb, peerId.lsb)); + } + } + } + + public String getVoiceUsername(EaglercraftUUID uuid) { + VoicePlayerState state = voicePlayers.get(uuid); + if (state != null) { + return state.name; + } else { + return uuid.toString(); + } + } + + public EnumVoiceChannelStatus getVoiceStatus() { + if (voiceChannel != EnumVoiceChannelType.NONE) { + return PlatformVoiceClient.getReadyState() != EnumVoiceChannelReadyState.DEVICE_INITIALIZED ? + EnumVoiceChannelStatus.CONNECTING : EnumVoiceChannelStatus.CONNECTED; + } else { + return EnumVoiceChannelStatus.DISCONNECTED; + } + } + + public void tickVoiceClient() { + if (voiceChannel == EnumVoiceChannelType.GLOBAL) { + long millis = EagRuntime.steadyTimeMillis(); + if (millis - lastUpdate > 1500l) { + lastUpdate = millis; + for (VoicePlayerState state : voicePlayers.values()) { + state.tryRequest(millis); + } + } + } else if (voiceChannel == EnumVoiceChannelType.PROXIMITY) { + long millis = EagRuntime.steadyTimeMillis(); + if (millis - lastUpdate > 100l) { + lastUpdate = millis; + for (VoicePlayerState state : voicePlayers.values()) { + boolean old = state.nearby; + recheckNearby(state); + if (state.nearby) { + state.tryRequest(millis); + } else if (old) { + PlatformVoiceClient.signalDisconnect(state.uuid, false); + } + } + } + } + } + + public void release() { + for (VoicePlayerState state : new ArrayList<>(voicePlayers.values())) { + dropPlayer(state.uuid); + } + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoicePlayerState.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoicePlayerState.java new file mode 100644 index 00000000..3c51adbe --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoicePlayerState.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 lax1dude, ayunami2000. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.voice; + +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; + +public class VoicePlayerState { + + public final VoiceClientInstance client; + public final EaglercraftUUID uuid; + public long lastRequest = -15000l; + public String name = null; + public boolean nearby = false; + + public VoicePlayerState(VoiceClientInstance client, EaglercraftUUID uuid) { + this.client = client; + this.uuid = uuid; + } + + public void tryRequest(long millis) { + if (!VoiceClientController.getVoiceListening().contains(uuid)) { + if (millis - lastRequest > 4000l) { + lastRequest = millis; + client.sendPacketRequest(this); + } + } + } + + public void handleDisconnect() { + lastRequest = 0l; + } + + public boolean isListening() { + return VoiceClientController.getVoiceListening().contains(uuid); + } + +} diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenPhishingWarning.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenPhishingWarning.java index 49433973..bdd33281 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenPhishingWarning.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenPhishingWarning.java @@ -40,17 +40,17 @@ public class GuiScreenPhishingWarning extends GuiScreen { public void initGui() { this.buttonList.clear(); - this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 134, I18n.format("webviewPhishingWaring.continue"))); + this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 134, I18n.format("webviewPhishingWarning.continue"))); } public void drawScreen(int mx, int my, float pt) { this.drawDefaultBackground(); - this.drawCenteredString(fontRendererObj, EnumChatFormatting.BOLD + I18n.format("webviewPhishingWaring.title"), this.width / 2, 70, 0xFF4444); - this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWaring.text0"), this.width / 2, 90, 16777215); - this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWaring.text1"), this.width / 2, 102, 16777215); - this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWaring.text2"), this.width / 2, 114, 16777215); + this.drawCenteredString(fontRendererObj, EnumChatFormatting.BOLD + I18n.format("webviewPhishingWarning.title"), this.width / 2, 70, 0xFF4444); + this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWarning.text0"), this.width / 2, 90, 16777215); + this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWarning.text1"), this.width / 2, 102, 16777215); + this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWarning.text2"), this.width / 2, 114, 16777215); - String dontShowAgain = I18n.format("webviewPhishingWaring.dontShowAgain"); + String dontShowAgain = I18n.format("webviewPhishingWarning.dontShowAgain"); int w = fontRendererObj.getStringWidth(dontShowAgain) + 20; int ww = (this.width - w) / 2; this.drawString(fontRendererObj, dontShowAgain, ww + 20, 137, 0xCCCCCC); diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRecieveServerInfo.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRecieveServerInfo.java index c4b095bb..9d365dc9 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRecieveServerInfo.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRecieveServerInfo.java @@ -23,6 +23,7 @@ import java.util.Arrays; import net.lax1dude.eaglercraft.v1_8.EaglerInputStream; import net.lax1dude.eaglercraft.v1_8.EaglerZLIB; +import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; import net.lax1dude.eaglercraft.v1_8.IOUtils; import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest; import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions; @@ -34,6 +35,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketRequestServerInfoV4EAG; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.resources.I18n; @@ -44,13 +46,25 @@ public class GuiScreenRecieveServerInfo extends GuiScreen { protected final GuiScreen parent; protected final byte[] expectHash; + protected final IDisplayWebviewProc proc; protected int timer; protected int timer2; protected String statusString = "recieveServerInfo.checkingCache"; + public static interface IDisplayWebviewProc { + GuiScreen display(GuiScreen parent, byte[] blob, EaglercraftUUID permissionsOriginUUID); + } + public GuiScreenRecieveServerInfo(GuiScreen parent, byte[] expectHash) { this.parent = parent; this.expectHash = expectHash; + this.proc = GuiScreenServerInfo::createForCurrentState; + } + + public GuiScreenRecieveServerInfo(GuiScreen parent, byte[] expectHash, IDisplayWebviewProc proc) { + this.parent = parent; + this.expectHash = expectHash; + this.proc = proc; } public void initGui() { @@ -105,28 +119,26 @@ public class GuiScreenRecieveServerInfo extends GuiScreen { mc.displayGuiScreen(parent); return; } + NetHandlerPlayClient sendQueue = mc.thePlayer.sendQueue; ++timer; if(timer == 1) { byte[] data = ServerInfoCache.loadFromCache(expectHash); if(data != null) { - mc.displayGuiScreen(GuiScreenServerInfo.createForCurrentState(parent, data, WebViewOptions.getEmbedOriginUUID(expectHash))); + mc.displayGuiScreen(proc.display(parent, data, WebViewOptions.getEmbedOriginUUID(expectHash))); }else { - byte[] b = mc.thePlayer.sendQueue.cachedServerInfoData; - if(b != null) { + byte[] b = sendQueue.cachedServerInfoData; + if(b != null && Arrays.equals(expectHash, sendQueue.cachedServerInfoHash)) { if(b.length == 0) { mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent)); }else { ServerInfoCache.storeInCache(expectHash, b); - mc.displayGuiScreen(GuiScreenServerInfo.createForCurrentState(parent, b, WebViewOptions.getEmbedOriginUUID(expectHash))); + mc.displayGuiScreen(proc.display(parent, b, WebViewOptions.getEmbedOriginUUID(expectHash))); } }else { statusString = "recieveServerInfo.contactingServer"; - if(!mc.thePlayer.sendQueue.hasRequestedServerInfo) { - if(!ServerInfoCache.hasLastChunk || !Arrays.equals(ServerInfoCache.chunkRecieveHash, expectHash)) { - ServerInfoCache.clearDownload(); - mc.thePlayer.sendQueue.sendEaglerMessage(new CPacketRequestServerInfoV4EAG(expectHash)); - mc.thePlayer.sendQueue.hasRequestedServerInfo = true; - } + if(!ServerInfoCache.hasLastChunk || !Arrays.equals(ServerInfoCache.chunkRecieveHash, expectHash)) { + ServerInfoCache.clearDownload(); + sendQueue.sendEaglerMessage(new CPacketRequestServerInfoV4EAG(expectHash)); } } } @@ -144,7 +156,8 @@ public class GuiScreenRecieveServerInfo extends GuiScreen { } if(i != ServerInfoCache.chunkCurrentSize) { logger.error("An unknown error occured!"); - mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0]; + sendQueue.cachedServerInfoHash = expectHash; + sendQueue.cachedServerInfoData = new byte[0]; mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent)); return; } @@ -154,14 +167,16 @@ public class GuiScreenRecieveServerInfo extends GuiScreen { int finalSize = (new DataInputStream(bis)).readInt(); if(finalSize < 0) { logger.error("The response data was corrupt, decompressed size is negative!"); - mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0]; + sendQueue.cachedServerInfoHash = expectHash; + sendQueue.cachedServerInfoData = new byte[0]; mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent)); return; } if(finalSize > ServerInfoCache.CACHE_MAX_SIZE * 2) { - logger.error("Failed to decompress/verify server info response! Size is massive, {} " + finalSize + " bytes reported!"); + logger.error("Failed to decompress/verify server info response! Size is massive, {} bytes reported!", finalSize); logger.error("Aborting decompression. Rejoin the server to try again."); - mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0]; + sendQueue.cachedServerInfoHash = expectHash; + sendQueue.cachedServerInfoData = new byte[0]; mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent)); return; } @@ -175,17 +190,20 @@ public class GuiScreenRecieveServerInfo extends GuiScreen { digest.doFinal(csum, 0); if(Arrays.equals(csum, expectHash)) { ServerInfoCache.storeInCache(csum, decompressed); - mc.thePlayer.sendQueue.cachedServerInfoData = decompressed; - mc.displayGuiScreen(GuiScreenServerInfo.createForCurrentState(parent, decompressed, WebViewOptions.getEmbedOriginUUID(expectHash))); + sendQueue.cachedServerInfoHash = expectHash; + sendQueue.cachedServerInfoData = decompressed; + mc.displayGuiScreen(proc.display(parent, decompressed, WebViewOptions.getEmbedOriginUUID(expectHash))); }else { logger.error("The data recieved from the server did not have the correct SHA1 checksum! Rejoin the server to try again."); - mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0]; + sendQueue.cachedServerInfoHash = expectHash; + sendQueue.cachedServerInfoData = new byte[0]; mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent)); } }catch(IOException ex) { logger.error("Failed to decompress/verify server info response! Rejoin the server to try again."); logger.error(ex); - mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0]; + sendQueue.cachedServerInfoHash = expectHash; + sendQueue.cachedServerInfoData = new byte[0]; mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent)); } } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRequestDisplay.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRequestDisplay.java new file mode 100644 index 00000000..40ce67b4 --- /dev/null +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRequestDisplay.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.lax1dude.eaglercraft.v1_8.webview; + +import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; + +public class GuiScreenRequestDisplay extends GuiScreen { + + private static final ResourceLocation beaconGuiTexture = new ResourceLocation("textures/gui/container/beacon.png"); + + private GuiScreen cont; + private GuiScreen back; + private NetHandlerPlayClient netHandler; + private boolean mouseOverCheck; + private boolean hasCheckedBox; + + public GuiScreenRequestDisplay(GuiScreen cont, GuiScreen back, NetHandlerPlayClient netHandler) { + this.cont = cont; + this.back = back; + this.netHandler = netHandler; + } + + public void initGui() { + this.buttonList.clear(); + this.buttonList.add(new GuiButton(0, this.width / 2 + 2, this.height / 6 + 122, 148, 20, I18n.format("webviewPhishingWarning.continue"))); + this.buttonList.add(new GuiButton(1, this.width / 2 - 150, this.height / 6 + 122, 148, 20, I18n.format("gui.cancel"))); + } + + public void drawScreen(int mx, int my, float pt) { + this.drawDefaultBackground(); + this.drawCenteredString(fontRendererObj, EnumChatFormatting.BOLD + I18n.format("webviewDisplayWarning.title"), this.width / 2, 70, 0xFF4444); + this.drawCenteredString(fontRendererObj, I18n.format("webviewDisplayWarning.text0"), this.width / 2, 90, 16777215); + this.drawCenteredString(fontRendererObj, I18n.format("webviewDisplayWarning.text1"), this.width / 2, 102, 16777215); + + String dontShowAgain = I18n.format("webviewPhishingWarning.dontShowAgain"); + int w = fontRendererObj.getStringWidth(dontShowAgain) + 20; + int ww = (this.width - w) / 2; + this.drawString(fontRendererObj, dontShowAgain, ww + 20, 125, 0xCCCCCC); + + mouseOverCheck = ww < mx && ww + 17 > mx && 121 < my && 138 > my; + + if(mouseOverCheck) { + GlStateManager.color(0.7f, 0.7f, 1.0f, 1.0f); + }else { + GlStateManager.color(0.6f, 0.6f, 0.6f, 1.0f); + } + + mc.getTextureManager().bindTexture(beaconGuiTexture); + + GlStateManager.pushMatrix(); + GlStateManager.scale(0.75f, 0.75f, 0.75f); + drawTexturedModalRect(ww * 4 / 3, 121 * 4 / 3, 22, 219, 22, 22); + GlStateManager.popMatrix(); + + if(hasCheckedBox) { + GlStateManager.pushMatrix(); + GlStateManager.color(1.1f, 1.1f, 1.1f, 1.0f); + GlStateManager.translate(0.5f, 0.5f, 0.0f); + drawTexturedModalRect(ww, 121, 90, 222, 16, 16); + GlStateManager.popMatrix(); + } + + super.drawScreen(mx, my, pt); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 0) { + if(hasCheckedBox) { + netHandler.allowedDisplayWebview = true; + netHandler.allowedDisplayWebviewYes = true; + } + mc.displayGuiScreen(cont); + }else if (par1GuiButton.id == 1) { + if(hasCheckedBox) { + netHandler.allowedDisplayWebview = true; + netHandler.allowedDisplayWebviewYes = false; + } + mc.displayGuiScreen(back); + } + } + + @Override + protected void mouseClicked(int mx, int my, int btn) { + if(btn == 0 && mouseOverCheck) { + hasCheckedBox = !hasCheckedBox; + mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F)); + return; + } + super.mouseClicked(mx, my, btn); + } + +} \ No newline at end of file diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfo.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfo.java index d404d3fe..14e16894 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfo.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfo.java @@ -26,6 +26,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage; +import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketDisplayWebViewURLV5EAG; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; @@ -91,6 +92,54 @@ public class GuiScreenServerInfo extends GuiScreen { opts.fallbackTitle = PauseMenuCustomizeState.serverInfoEmbedTitle; } + public static GuiScreen createForDisplayRequest(GuiScreen parent, int perms, String title, String url) { + URI urlObj; + try { + urlObj = new URI(url); + }catch(URISyntaxException ex) { + logger.error("Refusing to iframe an invalid URL: {}", url); + logger.error(ex); + return new GuiScreenGenericErrorMessage("webviewInvalidURL.title", "webviewInvalidURL.desc", parent); + } + return createForDisplayRequest(parent, perms, title, urlObj); + } + + public static GuiScreen createForDisplayRequest(GuiScreen parent, int perms, String title, URI url) { + boolean support = WebViewOverlayController.supported(); + boolean fallbackSupport = WebViewOverlayController.fallbackSupported(); + if(!support && !fallbackSupport) { + return new GuiScreenGenericErrorMessage("webviewNotSupported.title", "webviewNotSupported.desc", parent); + } + WebViewOptions opts = new WebViewOptions(); + opts.contentMode = EnumWebViewContentMode.URL_BASED; + opts.url = url; + setupState(opts, perms, title); + opts.permissionsOriginUUID = WebViewOptions.getURLOriginUUID(url); + return support ? new GuiScreenServerInfo(parent, opts) : new GuiScreenServerInfoDesktop(parent, opts); + } + + public static GuiScreen createForDisplayRequest(GuiScreen parent, int perms, String title, byte[] blob, + EaglercraftUUID permissionsOriginUUID) { + boolean support = WebViewOverlayController.supported(); + boolean fallbackSupport = WebViewOverlayController.fallbackSupported(); + if(!support && !fallbackSupport) { + return new GuiScreenGenericErrorMessage("webviewNotSupported.title", "webviewNotSupported.desc", parent); + } + WebViewOptions opts = new WebViewOptions(); + opts.contentMode = EnumWebViewContentMode.BLOB_BASED; + opts.blob = blob; + setupState(opts, perms, title); + opts.permissionsOriginUUID = permissionsOriginUUID; + return support ? new GuiScreenServerInfo(parent, opts) : new GuiScreenServerInfoDesktop(parent, opts); + } + + public static void setupState(WebViewOptions opts, int perms, String title) { + opts.scriptEnabled = (perms & SPacketDisplayWebViewURLV5EAG.FLAG_PERMS_JAVASCRIPT) != 0; + opts.strictCSPEnable = (perms & SPacketDisplayWebViewURLV5EAG.FLAG_PERMS_STRICT_CSP) != 0; + opts.serverMessageAPIEnabled = (perms & SPacketDisplayWebViewURLV5EAG.FLAG_PERMS_MESSAGE_API) != 0; + opts.fallbackTitle = title; + } + public void initGui() { ScaledResolution res = mc.scaledResolution; if(!isShowing) { @@ -118,8 +167,7 @@ public class GuiScreenServerInfo extends GuiScreen { public void drawScreen(int mx, int my, float pt) { drawDefaultBackground(); - drawCenteredString(fontRendererObj, PauseMenuCustomizeState.serverInfoEmbedTitle == null ? "Server Info" - : PauseMenuCustomizeState.serverInfoEmbedTitle, width / 2, 13, 0xFFFFFF); + drawCenteredString(fontRendererObj, opts.fallbackTitle == null ? "Server Info" : opts.fallbackTitle, width / 2, 13, 0xFFFFFF); super.drawScreen(mx, my, pt); } diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfoDesktop.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfoDesktop.java index 8da557a0..492be59d 100644 --- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfoDesktop.java +++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfoDesktop.java @@ -17,7 +17,6 @@ package net.lax1dude.eaglercraft.v1_8.webview; import net.lax1dude.eaglercraft.v1_8.EagRuntime; -import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState; import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; @@ -77,7 +76,8 @@ public class GuiScreenServerInfoDesktop extends GuiScreen { public void drawScreen(int mx, int my, float pt) { drawDefaultBackground(); - drawCenteredString(fontRendererObj, PauseMenuCustomizeState.serverInfoEmbedTitle, this.width / 2, 70, 16777215); + drawCenteredString(fontRendererObj, opts.fallbackTitle == null ? "Server Info" : opts.fallbackTitle, + this.width / 2, 70, 16777215); drawCenteredString(fontRendererObj, I18n.format("fallbackWebViewScreen.text0"), this.width / 2, 90, 11184810); String link = WebViewOverlayController.fallbackRunning() ? WebViewOverlayController.getFallbackURL() : I18n.format(hasStarted ? "fallbackWebViewScreen.exited" : "fallbackWebViewScreen.startingUp"); diff --git a/sources/main/java/org/apache/commons/lang3/AnnotationUtils.java b/sources/main/java/org/apache/commons/lang3/AnnotationUtils.java deleted file mode 100644 index 00dc093c..00000000 --- a/sources/main/java/org/apache/commons/lang3/AnnotationUtils.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; - -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import net.lax1dude.eaglercraft.v1_8.HString; - -/** - *

- * Helper methods for working with {@link Annotation} instances. - *

- * - *

- * This class contains various utility methods that make working with - * annotations simpler. - *

- * - *

- * {@link Annotation} instances are always proxy objects; unfortunately dynamic - * proxies cannot be depended upon to know how to implement certain methods in - * the same manner as would be done by "natural" {@link Annotation}s. The - * methods presented in this class can be used to avoid that possibility. It is - * of course also possible for dynamic proxies to actually delegate their e.g. - * {@link Annotation#equals(Object)}/{@link Annotation#hashCode()}/ - * {@link Annotation#toString()} implementations to {@link AnnotationUtils}. - *

- * - *

- * #ThreadSafe# - *

- * - * @since 3.0 - */ -public class AnnotationUtils { - - /** - * A style that prints annotations as recommended. - */ - private static final ToStringStyle TO_STRING_STYLE = new ToStringStyle() { - /** Serialization version */ - private static final long serialVersionUID = 1L; - - { - setDefaultFullDetail(true); - setArrayContentDetail(true); - setUseClassName(true); - setUseShortClassName(true); - setUseIdentityHashCode(false); - setContentStart("("); - setContentEnd(")"); - setFieldSeparator(", "); - setArrayStart("["); - setArrayEnd("]"); - } - - /** - * {@inheritDoc} - */ - @Override - protected String getShortClassName(final Class cls) { - return cls.getSimpleName(); - } - - /** - * {@inheritDoc} - */ - @Override - protected void appendDetail(final StringBuffer buffer, final String fieldName, Object value) { - if (value instanceof Annotation) { - value = AnnotationUtils.toString((Annotation) value); - } - super.appendDetail(buffer, fieldName, value); - } - - }; - - /** - *

- * {@code AnnotationUtils} instances should NOT be constructed in standard - * programming. Instead, the class should be used statically. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public AnnotationUtils() { - } - - // ----------------------------------------------------------------------- - /** - *

- * Checks if two annotations are equal using the criteria for equality presented - * in the {@link Annotation#equals(Object)} API docs. - *

- * - * @param a1 the first Annotation to compare, {@code null} returns {@code false} - * unless both are {@code null} - * @param a2 the second Annotation to compare, {@code null} returns - * {@code false} unless both are {@code null} - * @return {@code true} if the two annotations are {@code equal} or both - * {@code null} - */ - public static boolean equals(final Annotation a1, final Annotation a2) { - if (a1 == a2) { - return true; - } - if (a1 == null || a2 == null) { - return false; - } - final Class type1 = a1.annotationType(); - final Class type2 = a2.annotationType(); - Validate.notNull(type1, "Annotation %s with null annotationType()", a1); - Validate.notNull(type2, "Annotation %s with null annotationType()", a2); - if (!type1.equals(type2)) { - return false; - } - try { - for (final Method m : type1.getDeclaredMethods()) { - if (m.getParameterTypes().length == 0 && isValidAnnotationMemberType(m.getReturnType())) { - final Object v1 = m.invoke(a1); - final Object v2 = m.invoke(a2); - if (!memberEquals(m.getReturnType(), v1, v2)) { - return false; - } - } - } - } catch (final IllegalAccessException | InvocationTargetException ex) { - return false; - } - return true; - } - - /** - *

- * Generate a hash code for the given annotation using the algorithm presented - * in the {@link Annotation#hashCode()} API docs. - *

- * - * @param a the Annotation for a hash code calculation is desired, not - * {@code null} - * @return the calculated hash code - * @throws RuntimeException if an {@code Exception} is encountered during - * annotation member access - * @throws IllegalStateException if an annotation method invocation returns - * {@code null} - */ - public static int hashCode(final Annotation a) { - int result = 0; - final Class type = a.annotationType(); - for (final Method m : type.getDeclaredMethods()) { - try { - final Object value = m.invoke(a); - if (value == null) { - throw new IllegalStateException(HString.format("Annotation method %s returned null", m)); - } - result += hashMember(m.getName(), value); - } catch (final RuntimeException ex) { - throw ex; - } catch (final Exception ex) { - throw new RuntimeException(ex); - } - } - return result; - } - - /** - *

- * Generate a string representation of an Annotation, as suggested by - * {@link Annotation#toString()}. - *

- * - * @param a the annotation of which a string representation is desired - * @return the standard string representation of an annotation, not {@code null} - */ - public static String toString(final Annotation a) { - final ToStringBuilder builder = new ToStringBuilder(a, TO_STRING_STYLE); - for (final Method m : a.annotationType().getDeclaredMethods()) { - if (m.getParameterTypes().length > 0) { - continue; // wtf? - } - try { - builder.append(m.getName(), m.invoke(a)); - } catch (final RuntimeException ex) { - throw ex; - } catch (final Exception ex) { - throw new RuntimeException(ex); - } - } - return builder.build(); - } - - /** - *

- * Checks if the specified type is permitted as an annotation member. - *

- * - *

- * The Java language specification only permits certain types to be used in - * annotations. These include {@link String}, {@link Class}, primitive types, - * {@link Annotation}, {@link Enum}, and single-dimensional arrays of these - * types. - *

- * - * @param type the type to check, {@code null} - * @return {@code true} if the type is a valid type to use in an annotation - */ - public static boolean isValidAnnotationMemberType(Class type) { - if (type == null) { - return false; - } - if (type.isArray()) { - type = type.getComponentType(); - } - return type.isPrimitive() || type.isEnum() || type.isAnnotation() || String.class.equals(type) - || Class.class.equals(type); - } - - // besides modularity, this has the advantage of autoboxing primitives: - /** - * Helper method for generating a hash code for a member of an annotation. - * - * @param name the name of the member - * @param value the value of the member - * @return a hash code for this member - */ - private static int hashMember(final String name, final Object value) { - final int part1 = name.hashCode() * 127; - if (value.getClass().isArray()) { - return part1 ^ arrayMemberHash(value.getClass().getComponentType(), value); - } - if (value instanceof Annotation) { - return part1 ^ hashCode((Annotation) value); - } - return part1 ^ value.hashCode(); - } - - /** - * Helper method for checking whether two objects of the given type are equal. - * This method is used to compare the parameters of two annotation instances. - * - * @param type the type of the objects to be compared - * @param o1 the first object - * @param o2 the second object - * @return a flag whether these objects are equal - */ - private static boolean memberEquals(final Class type, final Object o1, final Object o2) { - if (o1 == o2) { - return true; - } - if (o1 == null || o2 == null) { - return false; - } - if (type.isArray()) { - return arrayMemberEquals(type.getComponentType(), o1, o2); - } - if (type.isAnnotation()) { - return equals((Annotation) o1, (Annotation) o2); - } - return o1.equals(o2); - } - - /** - * Helper method for comparing two objects of an array type. - * - * @param componentType the component type of the array - * @param o1 the first object - * @param o2 the second object - * @return a flag whether these objects are equal - */ - private static boolean arrayMemberEquals(final Class componentType, final Object o1, final Object o2) { - if (componentType.isAnnotation()) { - return annotationArrayMemberEquals((Annotation[]) o1, (Annotation[]) o2); - } - if (componentType.equals(Byte.TYPE)) { - return Arrays.equals((byte[]) o1, (byte[]) o2); - } - if (componentType.equals(Short.TYPE)) { - return Arrays.equals((short[]) o1, (short[]) o2); - } - if (componentType.equals(Integer.TYPE)) { - return Arrays.equals((int[]) o1, (int[]) o2); - } - if (componentType.equals(Character.TYPE)) { - return Arrays.equals((char[]) o1, (char[]) o2); - } - if (componentType.equals(Long.TYPE)) { - return Arrays.equals((long[]) o1, (long[]) o2); - } - if (componentType.equals(Float.TYPE)) { - return Arrays.equals((float[]) o1, (float[]) o2); - } - if (componentType.equals(Double.TYPE)) { - return Arrays.equals((double[]) o1, (double[]) o2); - } - if (componentType.equals(Boolean.TYPE)) { - return Arrays.equals((boolean[]) o1, (boolean[]) o2); - } - return Arrays.equals((Object[]) o1, (Object[]) o2); - } - - /** - * Helper method for comparing two arrays of annotations. - * - * @param a1 the first array - * @param a2 the second array - * @return a flag whether these arrays are equal - */ - private static boolean annotationArrayMemberEquals(final Annotation[] a1, final Annotation[] a2) { - if (a1.length != a2.length) { - return false; - } - for (int i = 0; i < a1.length; i++) { - if (!equals(a1[i], a2[i])) { - return false; - } - } - return true; - } - - /** - * Helper method for generating a hash code for an array. - * - * @param componentType the component type of the array - * @param o the array - * @return a hash code for the specified array - */ - private static int arrayMemberHash(final Class componentType, final Object o) { - if (componentType.equals(Byte.TYPE)) { - return Arrays.hashCode((byte[]) o); - } - if (componentType.equals(Short.TYPE)) { - return Arrays.hashCode((short[]) o); - } - if (componentType.equals(Integer.TYPE)) { - return Arrays.hashCode((int[]) o); - } - if (componentType.equals(Character.TYPE)) { - return Arrays.hashCode((char[]) o); - } - if (componentType.equals(Long.TYPE)) { - return Arrays.hashCode((long[]) o); - } - if (componentType.equals(Float.TYPE)) { - return Arrays.hashCode((float[]) o); - } - if (componentType.equals(Double.TYPE)) { - return Arrays.hashCode((double[]) o); - } - if (componentType.equals(Boolean.TYPE)) { - return Arrays.hashCode((boolean[]) o); - } - return Arrays.hashCode((Object[]) o); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/ArchUtils.java b/sources/main/java/org/apache/commons/lang3/ArchUtils.java deleted file mode 100644 index 82c9b4f3..00000000 --- a/sources/main/java/org/apache/commons/lang3/ArchUtils.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Stream; - -import org.apache.commons.lang3.arch.Processor; - -/** - * An utility class for the os.arch System Property. The class defines methods - * for identifying the architecture of the current JVM. - *

- * Important: The os.arch System Property returns the architecture used by the - * JVM not of the operating system. - *

- * - * @since 3.6 - */ -public class ArchUtils { - - private static final Map ARCH_TO_PROCESSOR; - - static { - ARCH_TO_PROCESSOR = new HashMap<>(); - init(); - } - - private static void init() { - init_X86_32Bit(); - init_X86_64Bit(); - init_IA64_32Bit(); - init_IA64_64Bit(); - init_PPC_32Bit(); - init_PPC_64Bit(); - } - - private static void init_X86_32Bit() { - final Processor processor = new Processor(Processor.Arch.BIT_32, Processor.Type.X86); - addProcessors(processor, "x86", "i386", "i486", "i586", "i686", "pentium"); - } - - private static void init_X86_64Bit() { - final Processor processor = new Processor(Processor.Arch.BIT_64, Processor.Type.X86); - addProcessors(processor, "x86_64", "amd64", "em64t", "universal"); - } - - private static void init_IA64_32Bit() { - final Processor processor = new Processor(Processor.Arch.BIT_32, Processor.Type.IA_64); - addProcessors(processor, "ia64_32", "ia64n"); - } - - private static void init_IA64_64Bit() { - final Processor processor = new Processor(Processor.Arch.BIT_64, Processor.Type.IA_64); - addProcessors(processor, "ia64", "ia64w"); - } - - private static void init_PPC_32Bit() { - final Processor processor = new Processor(Processor.Arch.BIT_32, Processor.Type.PPC); - addProcessors(processor, "ppc", "power", "powerpc", "power_pc", "power_rs"); - } - - private static void init_PPC_64Bit() { - final Processor processor = new Processor(Processor.Arch.BIT_64, Processor.Type.PPC); - addProcessors(processor, "ppc64", "power64", "powerpc64", "power_pc64", "power_rs64"); - } - - /** - * Adds the given {@link Processor} with the given key {@link String} to the - * map. - * - * @param key The key as {@link String}. - * @param processor The {@link Processor} to add. - * @throws IllegalStateException If the key already exists. - */ - private static void addProcessor(final String key, final Processor processor) { - if (ARCH_TO_PROCESSOR.containsKey(key)) { - throw new IllegalStateException("Key " + key + " already exists in processor map"); - } - ARCH_TO_PROCESSOR.put(key, processor); - } - - /** - * Adds the given {@link Processor} with the given keys to the map. - * - * @param keys The keys. - * @param processor The {@link Processor} to add. - * @throws IllegalStateException If the key already exists. - */ - private static void addProcessors(final Processor processor, final String... keys) { - Stream.of(keys).forEach(e -> addProcessor(e, processor)); - } - - /** - * Returns a {@link Processor} object of the current JVM. - * - *

- * Important: The os.arch System Property returns the architecture used by the - * JVM not of the operating system. - *

- * - * @return A {@link Processor} when supported, else {@code null}. - */ - public static Processor getProcessor() { - return getProcessor(SystemUtils.OS_ARCH); - } - - /** - * Returns a {@link Processor} object the given value {@link String}. The - * {@link String} must be like a value returned by the os.arch System Property. - * - * @param value A {@link String} like a value returned by the os.arch System - * Property. - * @return A {@link Processor} when it exists, else {@code null}. - */ - public static Processor getProcessor(final String value) { - return ARCH_TO_PROCESSOR.get(value); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/ArraySorter.java b/sources/main/java/org/apache/commons/lang3/ArraySorter.java deleted file mode 100644 index e4b56379..00000000 --- a/sources/main/java/org/apache/commons/lang3/ArraySorter.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.util.Arrays; -import java.util.Comparator; - -/** - * Sorts and returns arrays in the fluent style. - * - * @since 3.12.0 - */ -public class ArraySorter { - - /** - * Sorts and returns the given array. - * - * @param array the array to sort. - * @return the given array. - * @see Arrays#sort(byte[]) - */ - public static byte[] sort(final byte[] array) { - Arrays.sort(array); - return array; - } - - /** - * Sorts and returns the given array. - * - * @param array the array to sort. - * @return the given array. - * @see Arrays#sort(char[]) - */ - public static char[] sort(final char[] array) { - Arrays.sort(array); - return array; - } - - /** - * Sorts and returns the given array. - * - * @param array the array to sort. - * @return the given array. - * @see Arrays#sort(double[]) - */ - public static double[] sort(final double[] array) { - Arrays.sort(array); - return array; - } - - /** - * Sorts and returns the given array. - * - * @param array the array to sort. - * @return the given array. - * @see Arrays#sort(float[]) - */ - public static float[] sort(final float[] array) { - Arrays.sort(array); - return array; - } - - /** - * Sorts and returns the given array. - * - * @param array the array to sort. - * @return the given array. - * @see Arrays#sort(int[]) - */ - public static int[] sort(final int[] array) { - Arrays.sort(array); - return array; - } - - /** - * Sorts and returns the given array. - * - * @param array the array to sort. - * @return the given array. - * @see Arrays#sort(long[]) - */ - public static long[] sort(final long[] array) { - Arrays.sort(array); - return array; - } - - /** - * Sorts and returns the given array. - * - * @param array the array to sort. - * @return the given array. - * @see Arrays#sort(short[]) - */ - public static short[] sort(final short[] array) { - Arrays.sort(array); - return array; - } - - /** - * Sorts and returns the given array. - * - * @param the array type. - * @param array the array to sort. - * @return the given array. - * @see Arrays#sort(Object[]) - */ - public static T[] sort(final T[] array) { - Arrays.sort(array); - return array; - } - - /** - * Sorts and returns the given array. - * - * @param the array type. - * @param array the array to sort. - * @param comparator the comparator to determine the order of the array. A - * {@code null} value uses the elements' {@link Comparable - * natural ordering}. - * @return the given array. - * @see Arrays#sort(Object[]) - */ - public static T[] sort(final T[] array, final Comparator comparator) { - Arrays.sort(array, comparator); - return array; - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/BitField.java b/sources/main/java/org/apache/commons/lang3/BitField.java deleted file mode 100644 index 12bd4cf2..00000000 --- a/sources/main/java/org/apache/commons/lang3/BitField.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -/** - *

- * Supports operations on bit-mapped fields. Instances of this class can be used - * to store a flag or data within an {@code int}, {@code short} or {@code byte}. - *

- * - *

- * Each {@code BitField} is constructed with a mask value, which indicates the - * bits that will be used to store and retrieve the data for that field. For - * instance, the mask {@code 0xFF} indicates the least-significant byte should - * be used to store the data. - *

- * - *

- * As an example, consider a car painting machine that accepts paint - * instructions as integers. Bit fields can be used to encode this: - *

- * - *
- * // blue, green and red are 1 byte values (0-255) stored in the three least
- * // significant bytes
- * BitField blue = new BitField(0xFF);
- * BitField green = new BitField(0xFF00);
- * BitField red = new BitField(0xFF0000);
- *
- * // anyColor is a flag triggered if any color is used
- * BitField anyColor = new BitField(0xFFFFFF);
- *
- * // isMetallic is a single bit flag
- * BitField isMetallic = new BitField(0x1000000);
- * 
- * - *

- * Using these {@code BitField} instances, a paint instruction can be encoded - * into an integer: - *

- * - *
- * int paintInstruction = 0;
- * paintInstruction = red.setValue(paintInstruction, 35);
- * paintInstruction = green.setValue(paintInstruction, 100);
- * paintInstruction = blue.setValue(paintInstruction, 255);
- * 
- * - *

- * Flags and data can be retrieved from the integer: - *

- * - *
- * // Prints true if red, green or blue is non-zero
- * System.out.println(anyColor.isSet(paintInstruction)); // prints true
- *
- * // Prints value of red, green and blue
- * System.out.println(red.getValue(paintInstruction)); // prints 35
- * System.out.println(green.getValue(paintInstruction)); // prints 100
- * System.out.println(blue.getValue(paintInstruction)); // prints 255
- *
- * // Prints true if isMetallic was set
- * System.out.println(isMetallic.isSet(paintInstruction)); // prints false
- * 
- * - * @since 2.0 - */ -public class BitField { - - private final int _mask; - private final int _shift_count; - - /** - *

- * Creates a BitField instance. - *

- * - * @param mask the mask specifying which bits apply to this BitField. Bits that - * are set in this mask are the bits that this BitField operates on - */ - public BitField(final int mask) { - _mask = mask; - _shift_count = mask == 0 ? 0 : Integer.numberOfTrailingZeros(mask); - } - - /** - *

- * Obtains the value for the specified BitField, appropriately shifted right. - *

- * - *

- * Many users of a BitField will want to treat the specified bits as an int - * value, and will not want to be aware that the value is stored as a BitField - * (and so shifted left so many bits). - *

- * - * @see #setValue(int,int) - * @param holder the int data containing the bits we're interested in - * @return the selected bits, shifted right appropriately - */ - public int getValue(final int holder) { - return getRawValue(holder) >> _shift_count; - } - - /** - *

- * Obtains the value for the specified BitField, appropriately shifted right, as - * a short. - *

- * - *

- * Many users of a BitField will want to treat the specified bits as an int - * value, and will not want to be aware that the value is stored as a BitField - * (and so shifted left so many bits). - *

- * - * @see #setShortValue(short,short) - * @param holder the short data containing the bits we're interested in - * @return the selected bits, shifted right appropriately - */ - public short getShortValue(final short holder) { - return (short) getValue(holder); - } - - /** - *

- * Obtains the value for the specified BitField, unshifted. - *

- * - * @param holder the int data containing the bits we're interested in - * @return the selected bits - */ - public int getRawValue(final int holder) { - return holder & _mask; - } - - /** - *

- * Obtains the value for the specified BitField, unshifted. - *

- * - * @param holder the short data containing the bits we're interested in - * @return the selected bits - */ - public short getShortRawValue(final short holder) { - return (short) getRawValue(holder); - } - - /** - *

- * Returns whether the field is set or not. - *

- * - *

- * This is most commonly used for a single-bit field, which is often used to - * represent a boolean value; the results of using it for a multi-bit field is - * to determine whether *any* of its bits are set. - *

- * - * @param holder the int data containing the bits we're interested in - * @return {@code true} if any of the bits are set, else {@code false} - */ - public boolean isSet(final int holder) { - return (holder & _mask) != 0; - } - - /** - *

- * Returns whether all of the bits are set or not. - *

- * - *

- * This is a stricter test than {@link #isSet(int)}, in that all of the bits in - * a multi-bit set must be set for this method to return {@code true}. - *

- * - * @param holder the int data containing the bits we're interested in - * @return {@code true} if all of the bits are set, else {@code false} - */ - public boolean isAllSet(final int holder) { - return (holder & _mask) == _mask; - } - - /** - *

- * Replaces the bits with new values. - *

- * - * @see #getValue(int) - * @param holder the int data containing the bits we're interested in - * @param value the new value for the specified bits - * @return the value of holder with the bits from the value parameter replacing - * the old bits - */ - public int setValue(final int holder, final int value) { - return (holder & ~_mask) | ((value << _shift_count) & _mask); - } - - /** - *

- * Replaces the bits with new values. - *

- * - * @see #getShortValue(short) - * @param holder the short data containing the bits we're interested in - * @param value the new value for the specified bits - * @return the value of holder with the bits from the value parameter replacing - * the old bits - */ - public short setShortValue(final short holder, final short value) { - return (short) setValue(holder, value); - } - - /** - *

- * Clears the bits. - *

- * - * @param holder the int data containing the bits we're interested in - * @return the value of holder with the specified bits cleared (set to - * {@code 0}) - */ - public int clear(final int holder) { - return holder & ~_mask; - } - - /** - *

- * Clears the bits. - *

- * - * @param holder the short data containing the bits we're interested in - * @return the value of holder with the specified bits cleared (set to - * {@code 0}) - */ - public short clearShort(final short holder) { - return (short) clear(holder); - } - - /** - *

- * Clears the bits. - *

- * - * @param holder the byte data containing the bits we're interested in - * - * @return the value of holder with the specified bits cleared (set to - * {@code 0}) - */ - public byte clearByte(final byte holder) { - return (byte) clear(holder); - } - - /** - *

- * Sets the bits. - *

- * - * @param holder the int data containing the bits we're interested in - * @return the value of holder with the specified bits set to {@code 1} - */ - public int set(final int holder) { - return holder | _mask; - } - - /** - *

- * Sets the bits. - *

- * - * @param holder the short data containing the bits we're interested in - * @return the value of holder with the specified bits set to {@code 1} - */ - public short setShort(final short holder) { - return (short) set(holder); - } - - /** - *

- * Sets the bits. - *

- * - * @param holder the byte data containing the bits we're interested in - * - * @return the value of holder with the specified bits set to {@code 1} - */ - public byte setByte(final byte holder) { - return (byte) set(holder); - } - - /** - *

- * Sets a boolean BitField. - *

- * - * @param holder the int data containing the bits we're interested in - * @param flag indicating whether to set or clear the bits - * @return the value of holder with the specified bits set or cleared - */ - public int setBoolean(final int holder, final boolean flag) { - return flag ? set(holder) : clear(holder); - } - - /** - *

- * Sets a boolean BitField. - *

- * - * @param holder the short data containing the bits we're interested in - * @param flag indicating whether to set or clear the bits - * @return the value of holder with the specified bits set or cleared - */ - public short setShortBoolean(final short holder, final boolean flag) { - return flag ? setShort(holder) : clearShort(holder); - } - - /** - *

- * Sets a boolean BitField. - *

- * - * @param holder the byte data containing the bits we're interested in - * @param flag indicating whether to set or clear the bits - * @return the value of holder with the specified bits set or cleared - */ - public byte setByteBoolean(final byte holder, final boolean flag) { - return flag ? setByte(holder) : clearByte(holder); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/BooleanUtils.java b/sources/main/java/org/apache/commons/lang3/BooleanUtils.java deleted file mode 100644 index 63e78a56..00000000 --- a/sources/main/java/org/apache/commons/lang3/BooleanUtils.java +++ /dev/null @@ -1,1167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import org.apache.commons.lang3.math.NumberUtils; - -/** - *

- * Operations on boolean primitives and Boolean objects. - *

- * - *

- * This class tries to handle {@code null} input gracefully. An exception will - * not be thrown for a {@code null} input. Each method documents its behavior in - * more detail. - *

- * - *

- * #ThreadSafe# - *

- * - * @since 2.0 - */ -public class BooleanUtils { - /** - * The false String {@code "false"}. - * - * @since 3.12.0 - */ - public static final String FALSE = "false"; - - /** - * The no String {@code "no"}. - * - * @since 3.12.0 - */ - public static final String NO = "no"; - - /** - * The off String {@code "off"}. - * - * @since 3.12.0 - */ - public static final String OFF = "off"; - - /** - * The on String {@code "on"}. - * - * @since 3.12.0 - */ - public static final String ON = "on"; - - /** - * The true String {@code "true"}. - * - * @since 3.12.0 - */ - public static final String TRUE = "true"; - - /** - * The yes String {@code "yes"}. - * - * @since 3.12.0 - */ - public static final String YES = "yes"; - - /** - *

- * Performs an 'and' operation on a set of booleans. - *

- * - *
-	 *   BooleanUtils.and(true, true)         = true
-	 *   BooleanUtils.and(false, false)       = false
-	 *   BooleanUtils.and(true, false)        = false
-	 *   BooleanUtils.and(true, true, false)  = false
-	 *   BooleanUtils.and(true, true, true)   = true
-	 * 
- * - * @param array an array of {@code boolean}s - * @return the result of the logical 'and' operation. That is {@code false} if - * any of the parameters is {@code false} and {@code true} otherwise. - * @throws NullPointerException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty. - * @since 3.0.1 - */ - public static boolean and(final boolean... array) { - ObjectUtils.requireNonEmpty(array, "array"); - for (final boolean element : array) { - if (!element) { - return false; - } - } - return true; - } - - /** - * Returns a new array of possible values (like an enum would). - * - * @return a new array of possible values (like an enum would). - * @since 3.12.0 - */ - public static Boolean[] booleanValues() { - return new Boolean[] { Boolean.FALSE, Boolean.TRUE }; - } - - /** - *

- * Compares two {@code boolean} values. This is the same functionality as - * provided in Java 7. - *

- * - * @param x the first {@code boolean} to compare - * @param y the second {@code boolean} to compare - * @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if - * {@code !x && y}; and a value greater than {@code 0} if - * {@code x && !y} - * @since 3.4 - */ - public static int compare(final boolean x, final boolean y) { - if (x == y) { - return 0; - } - return x ? 1 : -1; - } - - /** - *

- * Checks if a {@code Boolean} value is {@code false}, handling {@code null} by - * returning {@code false}. - *

- * - *
-	 *   BooleanUtils.isFalse(Boolean.TRUE)  = false
-	 *   BooleanUtils.isFalse(Boolean.FALSE) = true
-	 *   BooleanUtils.isFalse(null)          = false
-	 * 
- * - * @param bool the boolean to check, null returns {@code false} - * @return {@code true} only if the input is non-{@code null} and {@code false} - * @since 2.1 - */ - public static boolean isFalse(final Boolean bool) { - return Boolean.FALSE.equals(bool); - } - - /** - *

- * Checks if a {@code Boolean} value is not {@code false}, handling - * {@code null} by returning {@code true}. - *

- * - *
-	 *   BooleanUtils.isNotFalse(Boolean.TRUE)  = true
-	 *   BooleanUtils.isNotFalse(Boolean.FALSE) = false
-	 *   BooleanUtils.isNotFalse(null)          = true
-	 * 
- * - * @param bool the boolean to check, null returns {@code true} - * @return {@code true} if the input is {@code null} or {@code true} - * @since 2.3 - */ - public static boolean isNotFalse(final Boolean bool) { - return !isFalse(bool); - } - - /** - *

- * Checks if a {@code Boolean} value is not {@code true}, handling - * {@code null} by returning {@code true}. - *

- * - *
-	 *   BooleanUtils.isNotTrue(Boolean.TRUE)  = false
-	 *   BooleanUtils.isNotTrue(Boolean.FALSE) = true
-	 *   BooleanUtils.isNotTrue(null)          = true
-	 * 
- * - * @param bool the boolean to check, null returns {@code true} - * @return {@code true} if the input is null or false - * @since 2.3 - */ - public static boolean isNotTrue(final Boolean bool) { - return !isTrue(bool); - } - - /** - *

- * Checks if a {@code Boolean} value is {@code true}, handling {@code null} by - * returning {@code false}. - *

- * - *
-	 *   BooleanUtils.isTrue(Boolean.TRUE)  = true
-	 *   BooleanUtils.isTrue(Boolean.FALSE) = false
-	 *   BooleanUtils.isTrue(null)          = false
-	 * 
- * - * @param bool the boolean to check, {@code null} returns {@code false} - * @return {@code true} only if the input is non-null and true - * @since 2.1 - */ - public static boolean isTrue(final Boolean bool) { - return Boolean.TRUE.equals(bool); - } - - /** - *

- * Negates the specified boolean. - *

- * - *

- * If {@code null} is passed in, {@code null} will be returned. - *

- * - *

- * NOTE: This returns {@code null} and will throw a {@code NullPointerException} - * if unboxed to a boolean. - *

- * - *
-	 * BooleanUtils.negate(Boolean.TRUE) = Boolean.FALSE;
-	 * BooleanUtils.negate(Boolean.FALSE) = Boolean.TRUE;
-	 * BooleanUtils.negate(null) = null;
-	 * 
- * - * @param bool the Boolean to negate, may be null - * @return the negated Boolean, or {@code null} if {@code null} input - */ - public static Boolean negate(final Boolean bool) { - if (bool == null) { - return null; - } - return bool.booleanValue() ? Boolean.FALSE : Boolean.TRUE; - } - - /** - *

- * Performs an 'or' operation on a set of booleans. - *

- * - *
-	 *   BooleanUtils.or(true, true)          = true
-	 *   BooleanUtils.or(false, false)        = false
-	 *   BooleanUtils.or(true, false)         = true
-	 *   BooleanUtils.or(true, true, false)   = true
-	 *   BooleanUtils.or(true, true, true)    = true
-	 *   BooleanUtils.or(false, false, false) = false
-	 * 
- * - * @param array an array of {@code boolean}s - * @return {@code true} if any of the arguments is {@code true}, and it returns - * {@code false} otherwise. - * @throws NullPointerException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty. - * @since 3.0.1 - */ - public static boolean or(final boolean... array) { - ObjectUtils.requireNonEmpty(array, "array"); - for (final boolean element : array) { - if (element) { - return true; - } - } - return false; - } - - /** - * Returns a new array of possible values (like an enum would). - * - * @return a new array of possible values (like an enum would). - * @since 3.12.0 - */ - public static boolean[] primitiveValues() { - return new boolean[] { false, true }; - } - - /** - *

- * Converts a Boolean to a boolean handling {@code null} by returning - * {@code false}. - *

- * - *
-	 *   BooleanUtils.toBoolean(Boolean.TRUE)  = true
-	 *   BooleanUtils.toBoolean(Boolean.FALSE) = false
-	 *   BooleanUtils.toBoolean(null)          = false
-	 * 
- * - * @param bool the boolean to convert - * @return {@code true} or {@code false}, {@code null} returns {@code false} - */ - public static boolean toBoolean(final Boolean bool) { - return bool != null && bool.booleanValue(); - } - - /** - *

- * Converts an int to a boolean using the convention that {@code zero} is - * {@code false}, everything else is {@code true}. - *

- * - *
-	 *   BooleanUtils.toBoolean(0) = false
-	 *   BooleanUtils.toBoolean(1) = true
-	 *   BooleanUtils.toBoolean(2) = true
-	 * 
- * - * @param value the int to convert - * @return {@code true} if non-zero, {@code false} if zero - */ - public static boolean toBoolean(final int value) { - return value != 0; - } - - /** - *

- * Converts an int to a boolean specifying the conversion values. - *

- * - *

- * If the {@code trueValue} and {@code falseValue} are the same number then the - * return value will be {@code true} in case {@code value} matches it. - *

- * - *
-	 *   BooleanUtils.toBoolean(0, 1, 0) = false
-	 *   BooleanUtils.toBoolean(1, 1, 0) = true
-	 *   BooleanUtils.toBoolean(1, 1, 1) = true
-	 *   BooleanUtils.toBoolean(2, 1, 2) = false
-	 *   BooleanUtils.toBoolean(2, 2, 0) = true
-	 * 
- * - * @param value the {@code Integer} to convert - * @param trueValue the value to match for {@code true} - * @param falseValue the value to match for {@code false} - * @return {@code true} or {@code false} - * @throws IllegalArgumentException if {@code value} does not match neither - * {@code trueValue} no {@code falseValue} - */ - public static boolean toBoolean(final int value, final int trueValue, final int falseValue) { - if (value == trueValue) { - return true; - } - if (value == falseValue) { - return false; - } - throw new IllegalArgumentException("The Integer did not match either specified value"); - } - - /** - *

- * Converts an Integer to a boolean specifying the conversion values. - *

- * - *
-	 *   BooleanUtils.toBoolean(Integer.valueOf(0), Integer.valueOf(1), Integer.valueOf(0)) = false
-	 *   BooleanUtils.toBoolean(Integer.valueOf(1), Integer.valueOf(1), Integer.valueOf(0)) = true
-	 *   BooleanUtils.toBoolean(Integer.valueOf(2), Integer.valueOf(1), Integer.valueOf(2)) = false
-	 *   BooleanUtils.toBoolean(Integer.valueOf(2), Integer.valueOf(2), Integer.valueOf(0)) = true
-	 *   BooleanUtils.toBoolean(null, null, Integer.valueOf(0))                     = true
-	 * 
- * - * @param value the Integer to convert - * @param trueValue the value to match for {@code true}, may be {@code null} - * @param falseValue the value to match for {@code false}, may be {@code null} - * @return {@code true} or {@code false} - * @throws IllegalArgumentException if no match - */ - public static boolean toBoolean(final Integer value, final Integer trueValue, final Integer falseValue) { - if (value == null) { - if (trueValue == null) { - return true; - } - if (falseValue == null) { - return false; - } - } else if (value.equals(trueValue)) { - return true; - } else if (value.equals(falseValue)) { - return false; - } - throw new IllegalArgumentException("The Integer did not match either specified value"); - } - - /** - *

- * Converts a String to a boolean (optimised for performance). - *

- * - *

- * {@code 'true'}, {@code 'on'}, {@code 'y'}, {@code 't'} or {@code 'yes'} (case - * insensitive) will return {@code true}. Otherwise, {@code false} is returned. - *

- * - *

- * This method performs 4 times faster (JDK1.4) than - * {@code Boolean.valueOf(String)}. However, this method accepts 'on' and 'yes', - * 't', 'y' as true values. - * - *

-	 *   BooleanUtils.toBoolean(null)    = false
-	 *   BooleanUtils.toBoolean("true")  = true
-	 *   BooleanUtils.toBoolean("TRUE")  = true
-	 *   BooleanUtils.toBoolean("tRUe")  = true
-	 *   BooleanUtils.toBoolean("on")    = true
-	 *   BooleanUtils.toBoolean("yes")   = true
-	 *   BooleanUtils.toBoolean("false") = false
-	 *   BooleanUtils.toBoolean("x gti") = false
-	 *   BooleanUtils.toBoolean("y") = true
-	 *   BooleanUtils.toBoolean("n") = false
-	 *   BooleanUtils.toBoolean("t") = true
-	 *   BooleanUtils.toBoolean("f") = false
-	 * 
- * - * @param str the String to check - * @return the boolean value of the string, {@code false} if no match or the - * String is null - */ - public static boolean toBoolean(final String str) { - return toBooleanObject(str) == Boolean.TRUE; - } - - /** - *

- * Converts a String to a Boolean throwing an exception if no match found. - *

- * - *
-	 *   BooleanUtils.toBoolean("true", "true", "false")  = true
-	 *   BooleanUtils.toBoolean("false", "true", "false") = false
-	 * 
- * - * @param str the String to check - * @param trueString the String to match for {@code true} (case sensitive), may - * be {@code null} - * @param falseString the String to match for {@code false} (case sensitive), - * may be {@code null} - * @return the boolean value of the string - * @throws IllegalArgumentException if the String doesn't match - */ - public static boolean toBoolean(final String str, final String trueString, final String falseString) { - if (str == trueString) { - return true; - } else if (str == falseString) { - return false; - } else if (str != null) { - if (str.equals(trueString)) { - return true; - } else if (str.equals(falseString)) { - return false; - } - } - throw new IllegalArgumentException("The String did not match either specified value"); - } - - /** - *

- * Converts a Boolean to a boolean handling {@code null}. - *

- * - *
-	 *   BooleanUtils.toBooleanDefaultIfNull(Boolean.TRUE, false)  = true
-	 *   BooleanUtils.toBooleanDefaultIfNull(Boolean.TRUE, true)   = true
-	 *   BooleanUtils.toBooleanDefaultIfNull(Boolean.FALSE, true)  = false
-	 *   BooleanUtils.toBooleanDefaultIfNull(Boolean.FALSE, false) = false
-	 *   BooleanUtils.toBooleanDefaultIfNull(null, true)           = true
-	 *   BooleanUtils.toBooleanDefaultIfNull(null, false)          = false
-	 * 
- * - * @param bool the boolean object to convert to primitive - * @param valueIfNull the boolean value to return if the parameter {@code bool} - * is {@code null} - * @return {@code true} or {@code false} - */ - public static boolean toBooleanDefaultIfNull(final Boolean bool, final boolean valueIfNull) { - if (bool == null) { - return valueIfNull; - } - return bool.booleanValue(); - } - - /** - *

- * Converts an int to a Boolean using the convention that {@code zero} is - * {@code false}, everything else is {@code true}. - *

- * - *
-	 *   BooleanUtils.toBoolean(0) = Boolean.FALSE
-	 *   BooleanUtils.toBoolean(1) = Boolean.TRUE
-	 *   BooleanUtils.toBoolean(2) = Boolean.TRUE
-	 * 
- * - * @param value the int to convert - * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero, {@code null} if - * {@code null} - */ - public static Boolean toBooleanObject(final int value) { - return value == 0 ? Boolean.FALSE : Boolean.TRUE; - } - - /** - *

- * Converts an int to a Boolean specifying the conversion values. - *

- * - *

- * NOTE: This method may return {@code null} and may throw a - * {@code NullPointerException} if unboxed to a {@code boolean}. - *

- * - *

- * The checks are done first for the {@code trueValue}, then for the - * {@code falseValue} and finally for the {@code nullValue}. - *

- * - *
-	 *   BooleanUtils.toBooleanObject(0, 0, 2, 3) = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject(0, 0, 0, 3) = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject(0, 0, 0, 0) = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject(2, 1, 2, 3) = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject(2, 1, 2, 2) = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject(3, 1, 2, 3) = null
-	 * 
- * - * @param value the Integer to convert - * @param trueValue the value to match for {@code true} - * @param falseValue the value to match for {@code false} - * @param nullValue the value to to match for {@code null} - * @return Boolean.TRUE, Boolean.FALSE, or {@code null} - * @throws IllegalArgumentException if no match - */ - public static Boolean toBooleanObject(final int value, final int trueValue, final int falseValue, - final int nullValue) { - if (value == trueValue) { - return Boolean.TRUE; - } - if (value == falseValue) { - return Boolean.FALSE; - } - if (value == nullValue) { - return null; - } - throw new IllegalArgumentException("The Integer did not match any specified value"); - } - - /** - *

- * Converts an Integer to a Boolean using the convention that {@code zero} is - * {@code false}, every other numeric value is {@code true}. - *

- * - *

- * {@code null} will be converted to {@code null}. - *

- * - *

- * NOTE: This method may return {@code null} and may throw a - * {@code NullPointerException} if unboxed to a {@code boolean}. - *

- * - *
-	 *   BooleanUtils.toBooleanObject(Integer.valueOf(0))    = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject(Integer.valueOf(1))    = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject(Integer.valueOf(null)) = null
-	 * 
- * - * @param value the Integer to convert - * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero, {@code null} if - * {@code null} input - */ - public static Boolean toBooleanObject(final Integer value) { - if (value == null) { - return null; - } - return value.intValue() == 0 ? Boolean.FALSE : Boolean.TRUE; - } - - /** - *

- * Converts an Integer to a Boolean specifying the conversion values. - *

- * - *

- * NOTE: This method may return {@code null} and may throw a - * {@code NullPointerException} if unboxed to a {@code boolean}. - *

- * - *

- * The checks are done first for the {@code trueValue}, then for the - * {@code falseValue} and finally for the {@code nullValue}. - *

- ** - *
-	 *   BooleanUtils.toBooleanObject(Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(2), Integer.valueOf(3)) = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject(Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(3)) = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject(Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0)) = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject(Integer.valueOf(2), Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)) = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject(Integer.valueOf(2), Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(2)) = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject(Integer.valueOf(3), Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)) = null
-	 * 
- * - * @param value the Integer to convert - * @param trueValue the value to match for {@code true}, may be {@code null} - * @param falseValue the value to match for {@code false}, may be {@code null} - * @param nullValue the value to to match for {@code null}, may be {@code null} - * @return Boolean.TRUE, Boolean.FALSE, or {@code null} - * @throws IllegalArgumentException if no match - */ - public static Boolean toBooleanObject(final Integer value, final Integer trueValue, final Integer falseValue, - final Integer nullValue) { - if (value == null) { - if (trueValue == null) { - return Boolean.TRUE; - } - if (falseValue == null) { - return Boolean.FALSE; - } - if (nullValue == null) { - return null; - } - } else if (value.equals(trueValue)) { - return Boolean.TRUE; - } else if (value.equals(falseValue)) { - return Boolean.FALSE; - } else if (value.equals(nullValue)) { - return null; - } - throw new IllegalArgumentException("The Integer did not match any specified value"); - } - - /** - *

- * Converts a String to a Boolean. - *

- * - *

- * {@code 'true'}, {@code 'on'}, {@code 'y'}, {@code 't'}, {@code 'yes'} or - * {@code '1'} (case insensitive) will return {@code true}. {@code 'false'}, - * {@code 'off'}, {@code 'n'}, {@code 'f'}, {@code 'no'} or {@code '0'} (case - * insensitive) will return {@code false}. Otherwise, {@code null} is returned. - *

- * - *

- * NOTE: This method may return {@code null} and may throw a - * {@code NullPointerException} if unboxed to a {@code boolean}. - *

- * - *
-	 *   // N.B. case is not significant
-	 *   BooleanUtils.toBooleanObject(null)    = null
-	 *   BooleanUtils.toBooleanObject("true")  = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject("T")     = Boolean.TRUE // i.e. T[RUE]
-	 *   BooleanUtils.toBooleanObject("false") = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject("f")     = Boolean.FALSE // i.e. f[alse]
-	 *   BooleanUtils.toBooleanObject("No")    = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject("n")     = Boolean.FALSE // i.e. n[o]
-	 *   BooleanUtils.toBooleanObject("on")    = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject("ON")    = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject("off")   = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject("oFf")   = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject("yes")   = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject("Y")     = Boolean.TRUE // i.e. Y[ES]
-	 *   BooleanUtils.toBooleanObject("1")     = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject("0")     = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject("blue")  = null
-	 *   BooleanUtils.toBooleanObject("true ") = null // trailing space (too long)
-	 *   BooleanUtils.toBooleanObject("ono")   = null // does not match on or no
-	 * 
- * - * @param str the String to check; upper and lower case are treated as the same - * @return the Boolean value of the string, {@code null} if no match or - * {@code null} input - */ - public static Boolean toBooleanObject(final String str) { - // Previously used equalsIgnoreCase, which was fast for interned 'true'. - // Non interned 'true' matched 15 times slower. - // - // Optimisation provides same performance as before for interned 'true'. - // Similar performance for null, 'false', and other strings not length 2/3/4. - // 'true'/'TRUE' match 4 times slower, 'tRUE'/'True' 7 times slower. - if (str == TRUE) { - return Boolean.TRUE; - } - if (str == null) { - return null; - } - switch (str.length()) { - case 1: { - final char ch0 = str.charAt(0); - if (ch0 == 'y' || ch0 == 'Y' || ch0 == 't' || ch0 == 'T' || ch0 == '1') { - return Boolean.TRUE; - } - if (ch0 == 'n' || ch0 == 'N' || ch0 == 'f' || ch0 == 'F' || ch0 == '0') { - return Boolean.FALSE; - } - break; - } - case 2: { - final char ch0 = str.charAt(0); - final char ch1 = str.charAt(1); - if ((ch0 == 'o' || ch0 == 'O') && (ch1 == 'n' || ch1 == 'N')) { - return Boolean.TRUE; - } - if ((ch0 == 'n' || ch0 == 'N') && (ch1 == 'o' || ch1 == 'O')) { - return Boolean.FALSE; - } - break; - } - case 3: { - final char ch0 = str.charAt(0); - final char ch1 = str.charAt(1); - final char ch2 = str.charAt(2); - if ((ch0 == 'y' || ch0 == 'Y') && (ch1 == 'e' || ch1 == 'E') && (ch2 == 's' || ch2 == 'S')) { - return Boolean.TRUE; - } - if ((ch0 == 'o' || ch0 == 'O') && (ch1 == 'f' || ch1 == 'F') && (ch2 == 'f' || ch2 == 'F')) { - return Boolean.FALSE; - } - break; - } - case 4: { - final char ch0 = str.charAt(0); - final char ch1 = str.charAt(1); - final char ch2 = str.charAt(2); - final char ch3 = str.charAt(3); - if ((ch0 == 't' || ch0 == 'T') && (ch1 == 'r' || ch1 == 'R') && (ch2 == 'u' || ch2 == 'U') - && (ch3 == 'e' || ch3 == 'E')) { - return Boolean.TRUE; - } - break; - } - case 5: { - final char ch0 = str.charAt(0); - final char ch1 = str.charAt(1); - final char ch2 = str.charAt(2); - final char ch3 = str.charAt(3); - final char ch4 = str.charAt(4); - if ((ch0 == 'f' || ch0 == 'F') && (ch1 == 'a' || ch1 == 'A') && (ch2 == 'l' || ch2 == 'L') - && (ch3 == 's' || ch3 == 'S') && (ch4 == 'e' || ch4 == 'E')) { - return Boolean.FALSE; - } - break; - } - default: - break; - } - - return null; - } - - /** - *

- * Converts a String to a Boolean throwing an exception if no match. - *

- * - *

- * NOTE: This method may return {@code null} and may throw a - * {@code NullPointerException} if unboxed to a {@code boolean}. - *

- * - *
-	 *   BooleanUtils.toBooleanObject("true", "true", "false", "null")   = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject(null, null, "false", "null")       = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject(null, null, null, "null")          = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject(null, null, null, null)            = Boolean.TRUE
-	 *   BooleanUtils.toBooleanObject("false", "true", "false", "null")  = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject("false", "true", "false", "false") = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject(null, "true", null, "false")       = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject(null, "true", null, null)          = Boolean.FALSE
-	 *   BooleanUtils.toBooleanObject("null", "true", "false", "null")   = null
-	 * 
- * - * @param str the String to check - * @param trueString the String to match for {@code true} (case sensitive), may - * be {@code null} - * @param falseString the String to match for {@code false} (case sensitive), - * may be {@code null} - * @param nullString the String to match for {@code null} (case sensitive), may - * be {@code null} - * @return the Boolean value of the string, {@code null} if either the String - * matches {@code nullString} or if {@code null} input and - * {@code nullString} is {@code null} - * @throws IllegalArgumentException if the String doesn't match - */ - public static Boolean toBooleanObject(final String str, final String trueString, final String falseString, - final String nullString) { - if (str == null) { - if (trueString == null) { - return Boolean.TRUE; - } - if (falseString == null) { - return Boolean.FALSE; - } - if (nullString == null) { - return null; - } - } else if (str.equals(trueString)) { - return Boolean.TRUE; - } else if (str.equals(falseString)) { - return Boolean.FALSE; - } else if (str.equals(nullString)) { - return null; - } - // no match - throw new IllegalArgumentException("The String did not match any specified value"); - } - - /** - *

- * Converts a boolean to an int using the convention that {@code true} is - * {@code 1} and {@code false} is {@code 0}. - *

- * - *
-	 *   BooleanUtils.toInteger(true)  = 1
-	 *   BooleanUtils.toInteger(false) = 0
-	 * 
- * - * @param bool the boolean to convert - * @return one if {@code true}, zero if {@code false} - */ - public static int toInteger(final boolean bool) { - return bool ? 1 : 0; - } - - /** - *

- * Converts a boolean to an int specifying the conversion values. - *

- * - *
-	 *   BooleanUtils.toInteger(true, 1, 0)  = 1
-	 *   BooleanUtils.toInteger(false, 1, 0) = 0
-	 * 
- * - * @param bool the to convert - * @param trueValue the value to return if {@code true} - * @param falseValue the value to return if {@code false} - * @return the appropriate value - */ - public static int toInteger(final boolean bool, final int trueValue, final int falseValue) { - return bool ? trueValue : falseValue; - } - - /** - *

- * Converts a Boolean to an int specifying the conversion values. - *

- * - *
-	 *   BooleanUtils.toInteger(Boolean.TRUE, 1, 0, 2)  = 1
-	 *   BooleanUtils.toInteger(Boolean.FALSE, 1, 0, 2) = 0
-	 *   BooleanUtils.toInteger(null, 1, 0, 2)          = 2
-	 * 
- * - * @param bool the Boolean to convert - * @param trueValue the value to return if {@code true} - * @param falseValue the value to return if {@code false} - * @param nullValue the value to return if {@code null} - * @return the appropriate value - */ - public static int toInteger(final Boolean bool, final int trueValue, final int falseValue, final int nullValue) { - if (bool == null) { - return nullValue; - } - return bool.booleanValue() ? trueValue : falseValue; - } - - /** - *

- * Converts a boolean to an Integer using the convention that {@code true} is - * {@code 1} and {@code false} is {@code 0}. - *

- * - *
-	 *   BooleanUtils.toIntegerObject(true)  = Integer.valueOf(1)
-	 *   BooleanUtils.toIntegerObject(false) = Integer.valueOf(0)
-	 * 
- * - * @param bool the boolean to convert - * @return one if {@code true}, zero if {@code false} - */ - public static Integer toIntegerObject(final boolean bool) { - return bool ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO; - } - - /** - *

- * Converts a boolean to an Integer specifying the conversion values. - *

- * - *
-	 *   BooleanUtils.toIntegerObject(true, Integer.valueOf(1), Integer.valueOf(0))  = Integer.valueOf(1)
-	 *   BooleanUtils.toIntegerObject(false, Integer.valueOf(1), Integer.valueOf(0)) = Integer.valueOf(0)
-	 * 
- * - * @param bool the to convert - * @param trueValue the value to return if {@code true}, may be {@code null} - * @param falseValue the value to return if {@code false}, may be {@code null} - * @return the appropriate value - */ - public static Integer toIntegerObject(final boolean bool, final Integer trueValue, final Integer falseValue) { - return bool ? trueValue : falseValue; - } - - /** - *

- * Converts a Boolean to a Integer using the convention that {@code zero} is - * {@code false}. - *

- * - *

- * {@code null} will be converted to {@code null}. - *

- * - *
-	 *   BooleanUtils.toIntegerObject(Boolean.TRUE)  = Integer.valueOf(1)
-	 *   BooleanUtils.toIntegerObject(Boolean.FALSE) = Integer.valueOf(0)
-	 * 
- * - * @param bool the Boolean to convert - * @return one if Boolean.TRUE, zero if Boolean.FALSE, {@code null} if - * {@code null} - */ - public static Integer toIntegerObject(final Boolean bool) { - if (bool == null) { - return null; - } - return bool.booleanValue() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO; - } - - /** - *

- * Converts a Boolean to an Integer specifying the conversion values. - *

- * - *
-	 *   BooleanUtils.toIntegerObject(Boolean.TRUE, Integer.valueOf(1), Integer.valueOf(0), Integer.valueOf(2))  = Integer.valueOf(1)
-	 *   BooleanUtils.toIntegerObject(Boolean.FALSE, Integer.valueOf(1), Integer.valueOf(0), Integer.valueOf(2)) = Integer.valueOf(0)
-	 *   BooleanUtils.toIntegerObject(null, Integer.valueOf(1), Integer.valueOf(0), Integer.valueOf(2))          = Integer.valueOf(2)
-	 * 
- * - * @param bool the Boolean to convert - * @param trueValue the value to return if {@code true}, may be {@code null} - * @param falseValue the value to return if {@code false}, may be {@code null} - * @param nullValue the value to return if {@code null}, may be {@code null} - * @return the appropriate value - */ - public static Integer toIntegerObject(final Boolean bool, final Integer trueValue, final Integer falseValue, - final Integer nullValue) { - if (bool == null) { - return nullValue; - } - return bool.booleanValue() ? trueValue : falseValue; - } - - /** - *

- * Converts a boolean to a String returning one of the input Strings. - *

- * - *
-	 *   BooleanUtils.toString(true, "true", "false")   = "true"
-	 *   BooleanUtils.toString(false, "true", "false")  = "false"
-	 * 
- * - * @param bool the Boolean to check - * @param trueString the String to return if {@code true}, may be {@code null} - * @param falseString the String to return if {@code false}, may be {@code null} - * @return one of the two input Strings - */ - public static String toString(final boolean bool, final String trueString, final String falseString) { - return bool ? trueString : falseString; - } - - /** - *

- * Converts a Boolean to a String returning one of the input Strings. - *

- * - *
-	 *   BooleanUtils.toString(Boolean.TRUE, "true", "false", null)   = "true"
-	 *   BooleanUtils.toString(Boolean.FALSE, "true", "false", null)  = "false"
-	 *   BooleanUtils.toString(null, "true", "false", null)           = null;
-	 * 
- * - * @param bool the Boolean to check - * @param trueString the String to return if {@code true}, may be {@code null} - * @param falseString the String to return if {@code false}, may be {@code null} - * @param nullString the String to return if {@code null}, may be {@code null} - * @return one of the three input Strings - */ - public static String toString(final Boolean bool, final String trueString, final String falseString, - final String nullString) { - if (bool == null) { - return nullString; - } - return bool.booleanValue() ? trueString : falseString; - } - - /** - *

- * Converts a boolean to a String returning {@code 'on'} or {@code 'off'}. - *

- * - *
-	 *   BooleanUtils.toStringOnOff(true)   = "on"
-	 *   BooleanUtils.toStringOnOff(false)  = "off"
-	 * 
- * - * @param bool the Boolean to check - * @return {@code 'on'}, {@code 'off'}, or {@code null} - */ - public static String toStringOnOff(final boolean bool) { - return toString(bool, ON, OFF); - } - - /** - *

- * Converts a Boolean to a String returning {@code 'on'}, {@code 'off'}, or - * {@code null}. - *

- * - *
-	 *   BooleanUtils.toStringOnOff(Boolean.TRUE)  = "on"
-	 *   BooleanUtils.toStringOnOff(Boolean.FALSE) = "off"
-	 *   BooleanUtils.toStringOnOff(null)          = null;
-	 * 
- * - * @param bool the Boolean to check - * @return {@code 'on'}, {@code 'off'}, or {@code null} - */ - public static String toStringOnOff(final Boolean bool) { - return toString(bool, ON, OFF, null); - } - - /** - *

- * Converts a boolean to a String returning {@code 'true'} or {@code 'false'}. - *

- * - *
-	 *   BooleanUtils.toStringTrueFalse(true)   = "true"
-	 *   BooleanUtils.toStringTrueFalse(false)  = "false"
-	 * 
- * - * @param bool the Boolean to check - * @return {@code 'true'}, {@code 'false'}, or {@code null} - */ - public static String toStringTrueFalse(final boolean bool) { - return toString(bool, TRUE, FALSE); - } - - /** - *

- * Converts a Boolean to a String returning {@code 'true'}, {@code 'false'}, or - * {@code null}. - *

- * - *
-	 *   BooleanUtils.toStringTrueFalse(Boolean.TRUE)  = "true"
-	 *   BooleanUtils.toStringTrueFalse(Boolean.FALSE) = "false"
-	 *   BooleanUtils.toStringTrueFalse(null)          = null;
-	 * 
- * - * @param bool the Boolean to check - * @return {@code 'true'}, {@code 'false'}, or {@code null} - */ - public static String toStringTrueFalse(final Boolean bool) { - return toString(bool, TRUE, FALSE, null); - } - - /** - *

- * Converts a boolean to a String returning {@code 'yes'} or {@code 'no'}. - *

- * - *
-	 *   BooleanUtils.toStringYesNo(true)   = "yes"
-	 *   BooleanUtils.toStringYesNo(false)  = "no"
-	 * 
- * - * @param bool the Boolean to check - * @return {@code 'yes'}, {@code 'no'}, or {@code null} - */ - public static String toStringYesNo(final boolean bool) { - return toString(bool, YES, NO); - } - - /** - *

- * Converts a Boolean to a String returning {@code 'yes'}, {@code 'no'}, or - * {@code null}. - *

- * - *
-	 *   BooleanUtils.toStringYesNo(Boolean.TRUE)  = "yes"
-	 *   BooleanUtils.toStringYesNo(Boolean.FALSE) = "no"
-	 *   BooleanUtils.toStringYesNo(null)          = null;
-	 * 
- * - * @param bool the Boolean to check - * @return {@code 'yes'}, {@code 'no'}, or {@code null} - */ - public static String toStringYesNo(final Boolean bool) { - return toString(bool, YES, NO, null); - } - - /** - *

- * Performs an xor on a set of booleans. - *

- * - *
-	 *   BooleanUtils.xor(true, true)   = false
-	 *   BooleanUtils.xor(false, false) = false
-	 *   BooleanUtils.xor(true, false)  = true
-	 * 
- * - * @param array an array of {@code boolean}s - * @return the result of the xor operations - * @throws NullPointerException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty. - */ - public static boolean xor(final boolean... array) { - ObjectUtils.requireNonEmpty(array, "array"); - // false if the neutral element of the xor operator - boolean result = false; - for (final boolean element : array) { - result ^= element; - } - - return result; - } - - /** - *

- * {@code BooleanUtils} instances should NOT be constructed in standard - * programming. Instead, the class should be used as - * {@code BooleanUtils.negate(true);}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public BooleanUtils() { - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/CharEncoding.java b/sources/main/java/org/apache/commons/lang3/CharEncoding.java deleted file mode 100644 index 34bbc631..00000000 --- a/sources/main/java/org/apache/commons/lang3/CharEncoding.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3; - -import java.nio.charset.Charset; -import java.nio.charset.IllegalCharsetNameException; - -/** - *

- * Character encoding names required of every implementation of the Java - * platform. - *

- * - *

- * According to JRE - * character encoding names: - *

- * - *

- * Every implementation of the Java platform is required to support the - * following character encodings. Consult the release documentation for your - * implementation to see if any other encodings are supported. - *

- * - * @see JRE - * character encoding names - * @since 2.1 - * @deprecated Java 7 introduced {@link java.nio.charset.StandardCharsets}, - * which defines these constants as {@link Charset} objects. Use - * {@link Charset#name()} to get the string values provided in this - * class. This class will be removed in a future release. - */ -@Deprecated -public class CharEncoding { - - /** - *

- * ISO Latin Alphabet #1, also known as ISO-LATIN-1. - *

- * - *

- * Every implementation of the Java platform is required to support this - * character encoding. - *

- */ - public static final String ISO_8859_1 = "ISO-8859-1"; - - /** - *

- * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block - * of the Unicode character set. - *

- * - *

- * Every implementation of the Java platform is required to support this - * character encoding. - *

- */ - public static final String US_ASCII = "US-ASCII"; - - /** - *

- * Sixteen-bit Unicode Transformation Format, byte order specified by a - * mandatory initial byte-order mark (either order accepted on input, big-endian - * used on output). - *

- * - *

- * Every implementation of the Java platform is required to support this - * character encoding. - *

- */ - public static final String UTF_16 = "UTF-16"; - - /** - *

- * Sixteen-bit Unicode Transformation Format, big-endian byte order. - *

- * - *

- * Every implementation of the Java platform is required to support this - * character encoding. - *

- */ - public static final String UTF_16BE = "UTF-16BE"; - - /** - *

- * Sixteen-bit Unicode Transformation Format, little-endian byte order. - *

- * - *

- * Every implementation of the Java platform is required to support this - * character encoding. - *

- */ - public static final String UTF_16LE = "UTF-16LE"; - - /** - *

- * Eight-bit Unicode Transformation Format. - *

- * - *

- * Every implementation of the Java platform is required to support this - * character encoding. - *

- */ - public static final String UTF_8 = "UTF-8"; - - /** - *

- * Returns whether the named charset is supported. - *

- * - *

- * This is similar to - * java.nio.charset.Charset.isSupported(String) but handles more formats - *

- * - * @param name the name of the requested charset; may be either a canonical name - * or an alias, null returns false - * @return {@code true} if the charset is available in the current Java virtual - * machine - * @deprecated Please use {@link Charset#isSupported(String)} instead, although - * be aware that {@code null} values are not accepted by that method - * and an {@link IllegalCharsetNameException} may be thrown. - */ - @Deprecated - public static boolean isSupported(final String name) { - if (name == null) { - return false; - } - try { - return Charset.isSupported(name); - } catch (final IllegalCharsetNameException ex) { - return false; - } - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/CharRange.java b/sources/main/java/org/apache/commons/lang3/CharRange.java deleted file mode 100644 index 49cfc197..00000000 --- a/sources/main/java/org/apache/commons/lang3/CharRange.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.io.Serializable; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - *

- * A contiguous range of characters, optionally negated. - *

- * - *

- * Instances are immutable. - *

- * - *

- * #ThreadSafe# - *

- * - * @since 1.0 - */ -// TODO: This is no longer public and will be removed later as CharSet is moved -// to depend on Range. -final class CharRange implements Iterable, Serializable { - - /** - * Required for serialization support. Lang version 2.0. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 8270183163158333422L; - - /** The first character, inclusive, in the range. */ - private final char start; - /** The last character, inclusive, in the range. */ - private final char end; - /** True if the range is everything except the characters specified. */ - private final boolean negated; - - /** Cached toString. */ - private transient String iToString; - - /** Empty array. */ - static final CharRange[] EMPTY_ARRAY = new CharRange[0]; - - /** - *

- * Constructs a {@code CharRange} over a set of characters, optionally negating - * the range. - *

- * - *

- * A negated range includes everything except that defined by the start and end - * characters. - *

- * - *

- * If start and end are in the wrong order, they are reversed. Thus {@code a-e} - * is the same as {@code e-a}. - *

- * - * @param start first character, inclusive, in this range - * @param end last character, inclusive, in this range - * @param negated true to express everything except the range - */ - private CharRange(char start, char end, final boolean negated) { - if (start > end) { - final char temp = start; - start = end; - end = temp; - } - - this.start = start; - this.end = end; - this.negated = negated; - } - - /** - *

- * Constructs a {@code CharRange} over a single character. - *

- * - * @param ch only character in this range - * @return the new CharRange object - * @since 2.5 - */ - public static CharRange is(final char ch) { - return new CharRange(ch, ch, false); - } - - /** - *

- * Constructs a negated {@code CharRange} over a single character. - *

- * - *

- * A negated range includes everything except that defined by the single - * character. - *

- * - * @param ch only character in this range - * @return the new CharRange object - * @since 2.5 - */ - public static CharRange isNot(final char ch) { - return new CharRange(ch, ch, true); - } - - /** - *

- * Constructs a {@code CharRange} over a set of characters. - *

- * - *

- * If start and end are in the wrong order, they are reversed. Thus {@code a-e} - * is the same as {@code e-a}. - *

- * - * @param start first character, inclusive, in this range - * @param end last character, inclusive, in this range - * @return the new CharRange object - * @since 2.5 - */ - public static CharRange isIn(final char start, final char end) { - return new CharRange(start, end, false); - } - - /** - *

- * Constructs a negated {@code CharRange} over a set of characters. - *

- * - *

- * A negated range includes everything except that defined by the start and end - * characters. - *

- * - *

- * If start and end are in the wrong order, they are reversed. Thus {@code a-e} - * is the same as {@code e-a}. - *

- * - * @param start first character, inclusive, in this range - * @param end last character, inclusive, in this range - * @return the new CharRange object - * @since 2.5 - */ - public static CharRange isNotIn(final char start, final char end) { - return new CharRange(start, end, true); - } - - // Accessors - // ----------------------------------------------------------------------- - /** - *

- * Gets the start character for this character range. - *

- * - * @return the start char (inclusive) - */ - public char getStart() { - return this.start; - } - - /** - *

- * Gets the end character for this character range. - *

- * - * @return the end char (inclusive) - */ - public char getEnd() { - return this.end; - } - - /** - *

- * Is this {@code CharRange} negated. - *

- * - *

- * A negated range includes everything except that defined by the start and end - * characters. - *

- * - * @return {@code true} if negated - */ - public boolean isNegated() { - return negated; - } - - // Contains - // ----------------------------------------------------------------------- - /** - *

- * Is the character specified contained in this range. - *

- * - * @param ch the character to check - * @return {@code true} if this range contains the input character - */ - public boolean contains(final char ch) { - return (ch >= start && ch <= end) != negated; - } - - /** - *

- * Are all the characters of the passed in range contained in this range. - *

- * - * @param range the range to check against - * @return {@code true} if this range entirely contains the input range - * @throws IllegalArgumentException if {@code null} input - */ - public boolean contains(final CharRange range) { - Validate.notNull(range, "range"); - if (negated) { - if (range.negated) { - return start >= range.start && end <= range.end; - } - return range.end < start || range.start > end; - } - if (range.negated) { - return start == 0 && end == Character.MAX_VALUE; - } - return start <= range.start && end >= range.end; - } - - // Basics - // ----------------------------------------------------------------------- - /** - *

- * Compares two CharRange objects, returning true if they represent exactly the - * same range of characters defined in the same way. - *

- * - * @param obj the object to compare to - * @return true if equal - */ - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof CharRange)) { - return false; - } - final CharRange other = (CharRange) obj; - return start == other.start && end == other.end && negated == other.negated; - } - - /** - *

- * Gets a hashCode compatible with the equals method. - *

- * - * @return a suitable hashCode - */ - @Override - public int hashCode() { - return 83 + start + 7 * end + (negated ? 1 : 0); - } - - /** - *

- * Gets a string representation of the character range. - *

- * - * @return string representation of this range - */ - @Override - public String toString() { - if (iToString == null) { - final StringBuilder buf = new StringBuilder(4); - if (isNegated()) { - buf.append('^'); - } - buf.append(start); - if (start != end) { - buf.append('-'); - buf.append(end); - } - iToString = buf.toString(); - } - return iToString; - } - - // Expansions - // ----------------------------------------------------------------------- - /** - *

- * Returns an iterator which can be used to walk through the characters - * described by this range. - *

- * - *

- * #NotThreadSafe# the iterator is not thread-safe - *

- * - * @return an iterator to the chars represented by this range - * @since 2.5 - */ - @Override - public Iterator iterator() { - return new CharacterIterator(this); - } - - /** - * Character {@link Iterator}. - *

- * #NotThreadSafe# - *

- */ - private static class CharacterIterator implements Iterator { - /** The current character */ - private char current; - - private final CharRange range; - private boolean hasNext; - - /** - * Constructs a new iterator for the character range. - * - * @param r The character range - */ - private CharacterIterator(final CharRange r) { - range = r; - hasNext = true; - - if (range.negated) { - if (range.start == 0) { - if (range.end == Character.MAX_VALUE) { - // This range is an empty set - hasNext = false; - } else { - current = (char) (range.end + 1); - } - } else { - current = 0; - } - } else { - current = range.start; - } - } - - /** - * Prepares the next character in the range. - */ - private void prepareNext() { - if (range.negated) { - if (current == Character.MAX_VALUE) { - hasNext = false; - } else if (current + 1 == range.start) { - if (range.end == Character.MAX_VALUE) { - hasNext = false; - } else { - current = (char) (range.end + 1); - } - } else { - current = (char) (current + 1); - } - } else if (current < range.end) { - current = (char) (current + 1); - } else { - hasNext = false; - } - } - - /** - * Has the iterator not reached the end character yet? - * - * @return {@code true} if the iterator has yet to reach the character date - */ - @Override - public boolean hasNext() { - return hasNext; - } - - /** - * Returns the next character in the iteration - * - * @return {@code Character} for the next character - */ - @Override - public Character next() { - if (!hasNext) { - throw new NoSuchElementException(); - } - final char cur = current; - prepareNext(); - return Character.valueOf(cur); - } - - /** - * Always throws UnsupportedOperationException. - * - * @throws UnsupportedOperationException Always thrown. - * @see java.util.Iterator#remove() - */ - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } -} diff --git a/sources/main/java/org/apache/commons/lang3/CharSequenceUtils.java b/sources/main/java/org/apache/commons/lang3/CharSequenceUtils.java deleted file mode 100644 index d8767d92..00000000 --- a/sources/main/java/org/apache/commons/lang3/CharSequenceUtils.java +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -/** - *

- * Operations on {@link CharSequence} that are {@code null} safe. - *

- * - * @see CharSequence - * @since 3.0 - */ -public class CharSequenceUtils { - - private static final int NOT_FOUND = -1; - - /** - *

- * {@code CharSequenceUtils} instances should NOT be constructed in standard - * programming. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public CharSequenceUtils() { - } - - // ----------------------------------------------------------------------- - /** - *

- * Returns a new {@code CharSequence} that is a subsequence of this sequence - * starting with the {@code char} value at the specified index. - *

- * - *

- * This provides the {@code CharSequence} equivalent to - * {@link String#substring(int)}. The length (in {@code char}) of the returned - * sequence is {@code length() - start}, so if {@code start == end} then an - * empty sequence is returned. - *

- * - * @param cs the specified subsequence, null returns null - * @param start the start index, inclusive, valid - * @return a new subsequence, may be null - * @throws IndexOutOfBoundsException if {@code start} is negative or if - * {@code start} is greater than - * {@code length()} - */ - public static CharSequence subSequence(final CharSequence cs, final int start) { - return cs == null ? null : cs.subSequence(start, cs.length()); - } - - // ----------------------------------------------------------------------- - /** - * Returns the index within {@code cs} of the first occurrence of the specified - * character, starting the search at the specified index. - *

- * If a character with value {@code searchChar} occurs in the character sequence - * represented by the {@code cs} object at an index no smaller than - * {@code start}, then the index of the first such occurrence is returned. For - * values of {@code searchChar} in the range from 0 to 0xFFFF (inclusive), this - * is the smallest value k such that:

- * - *
-	 * (this.charAt(k) == searchChar) && (k >= start)
-	 * 
- * - *
is true. For other values of {@code searchChar}, it is the - * smallest value k such that:
- * - *
-	 * (this.codePointAt(k) == searchChar) && (k >= start)
-	 * 
- * - *
is true. In either case, if no such character occurs inm - * {@code cs} at or after position {@code start}, then {@code -1} is returned. - * - *

- * There is no restriction on the value of {@code start}. If it is negative, it - * has the same effect as if it were zero: the entire {@code CharSequence} may - * be searched. If it is greater than the length of {@code cs}, it has the same - * effect as if it were equal to the length of {@code cs}: {@code -1} is - * returned. - * - *

- * All indices are specified in {@code char} values (Unicode code units). - * - * @param cs the {@code CharSequence} to be processed, not null - * @param searchChar the char to be searched for - * @param start the start index, negative starts at the string start - * @return the index where the search char was found, -1 if not found - * @since 3.6 updated to behave more like {@code String} - */ - static int indexOf(final CharSequence cs, final int searchChar, int start) { - if (cs instanceof String) { - return ((String) cs).indexOf(searchChar, start); - } - final int sz = cs.length(); - if (start < 0) { - start = 0; - } - if (searchChar < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - for (int i = start; i < sz; i++) { - if (cs.charAt(i) == searchChar) { - return i; - } - } - return NOT_FOUND; - } - // supplementary characters (LANG1300) - if (searchChar <= Character.MAX_CODE_POINT) { - final char[] chars = Character.toChars(searchChar); - for (int i = start; i < sz - 1; i++) { - final char high = cs.charAt(i); - final char low = cs.charAt(i + 1); - if (high == chars[0] && low == chars[1]) { - return i; - } - } - } - return NOT_FOUND; - } - - /** - * Used by the indexOf(CharSequence methods) as a green implementation of - * indexOf. - * - * @param cs the {@code CharSequence} to be processed - * @param searchChar the {@code CharSequence} to be searched for - * @param start the start index - * @return the index where the search sequence was found - */ - static int indexOf(final CharSequence cs, final CharSequence searchChar, final int start) { - if (cs instanceof String) { - return ((String) cs).indexOf(searchChar.toString(), start); - } else if (cs instanceof StringBuilder) { - return ((StringBuilder) cs).indexOf(searchChar.toString(), start); - } else if (cs instanceof StringBuffer) { - return ((StringBuffer) cs).indexOf(searchChar.toString(), start); - } - return cs.toString().indexOf(searchChar.toString(), start); -// if (cs instanceof String && searchChar instanceof String) { -// // TODO: Do we assume searchChar is usually relatively small; -// // If so then calling toString() on it is better than reverting to -// // the green implementation in the else block -// return ((String) cs).indexOf((String) searchChar, start); -// } else { -// // TODO: Implement rather than convert to String -// return cs.toString().indexOf(searchChar.toString(), start); -// } - } - - /** - * Returns the index within {@code cs} of the last occurrence of the specified - * character, searching backward starting at the specified index. For values of - * {@code searchChar} in the range from 0 to 0xFFFF (inclusive), the index - * returned is the largest value k such that:

- * - *
-	 * (this.charAt(k) == searchChar) && (k <= start)
-	 * 
- * - *
is true. For other values of {@code searchChar}, it is the - * largest value k such that:
- * - *
-	 * (this.codePointAt(k) == searchChar) && (k <= start)
-	 * 
- * - *
is true. In either case, if no such character occurs in - * {@code cs} at or before position {@code start}, then {@code -1} is returned. - * - *

- * All indices are specified in {@code char} values (Unicode code units). - * - * @param cs the {@code CharSequence} to be processed - * @param searchChar the char to be searched for - * @param start the start index, negative returns -1, beyond length starts - * at end - * @return the index where the search char was found, -1 if not found - * @since 3.6 updated to behave more like {@code String} - */ - static int lastIndexOf(final CharSequence cs, final int searchChar, int start) { - if (cs instanceof String) { - return ((String) cs).lastIndexOf(searchChar, start); - } - final int sz = cs.length(); - if (start < 0) { - return NOT_FOUND; - } - if (start >= sz) { - start = sz - 1; - } - if (searchChar < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - for (int i = start; i >= 0; --i) { - if (cs.charAt(i) == searchChar) { - return i; - } - } - return NOT_FOUND; - } - // supplementary characters (LANG1300) - // NOTE - we must do a forward traversal for this to avoid duplicating code - // points - if (searchChar <= Character.MAX_CODE_POINT) { - final char[] chars = Character.toChars(searchChar); - // make sure it's not the last index - if (start == sz - 1) { - return NOT_FOUND; - } - for (int i = start; i >= 0; i--) { - final char high = cs.charAt(i); - final char low = cs.charAt(i + 1); - if (chars[0] == high && chars[1] == low) { - return i; - } - } - } - return NOT_FOUND; - } - - static final int TO_STRING_LIMIT = 16; - - /** - * Used by the lastIndexOf(CharSequence methods) as a green implementation of - * lastIndexOf - * - * @param cs the {@code CharSequence} to be processed - * @param searchChar the {@code CharSequence} to find - * @param start the start index - * @return the index where the search sequence was found - */ - static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, int start) { - if (searchChar == null || cs == null) { - return NOT_FOUND; - } - if (searchChar instanceof String) { - if (cs instanceof String) { - return ((String) cs).lastIndexOf((String) searchChar, start); - } else if (cs instanceof StringBuilder) { - return ((StringBuilder) cs).lastIndexOf((String) searchChar, start); - } else if (cs instanceof StringBuffer) { - return ((StringBuffer) cs).lastIndexOf((String) searchChar, start); - } - } - - final int len1 = cs.length(); - final int len2 = searchChar.length(); - - if (start > len1) { - start = len1; - } - - if (start < 0 || len2 < 0 || len2 > len1) { - return NOT_FOUND; - } - - if (len2 == 0) { - return start; - } - - if (len2 <= TO_STRING_LIMIT) { - if (cs instanceof String) { - return ((String) cs).lastIndexOf(searchChar.toString(), start); - } else if (cs instanceof StringBuilder) { - return ((StringBuilder) cs).lastIndexOf(searchChar.toString(), start); - } else if (cs instanceof StringBuffer) { - return ((StringBuffer) cs).lastIndexOf(searchChar.toString(), start); - } - } - - if (start + len2 > len1) { - start = len1 - len2; - } - - final char char0 = searchChar.charAt(0); - - int i = start; - while (true) { - while (cs.charAt(i) != char0) { - i--; - if (i < 0) { - return NOT_FOUND; - } - } - if (checkLaterThan1(cs, searchChar, len2, i)) { - return i; - } - i--; - if (i < 0) { - return NOT_FOUND; - } - } - } - - private static boolean checkLaterThan1(final CharSequence cs, final CharSequence searchChar, final int len2, - final int start1) { - for (int i = 1, j = len2 - 1; i <= j; i++, j--) { - if (cs.charAt(start1 + i) != searchChar.charAt(i) || cs.charAt(start1 + j) != searchChar.charAt(j)) { - return false; - } - } - return true; - } - - /** - * Converts the given CharSequence to a char[]. - * - * @param source the {@code CharSequence} to be processed. - * @return the resulting char array, never null. - * @since 3.11 - */ - public static char[] toCharArray(final CharSequence source) { - final int len = StringUtils.length(source); - if (len == 0) { - return new char[0]; - } - if (source instanceof String) { - return ((String) source).toCharArray(); - } - final char[] array = new char[len]; - for (int i = 0; i < len; i++) { - array[i] = source.charAt(i); - } - return array; - } - - /** - * Green implementation of regionMatches. - * - * @param cs the {@code CharSequence} to be processed - * @param ignoreCase whether or not to be case insensitive - * @param thisStart the index to start on the {@code cs} CharSequence - * @param substring the {@code CharSequence} to be looked for - * @param start the index to start on the {@code substring} CharSequence - * @param length character length of the region - * @return whether the region matched - */ - static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart, - final CharSequence substring, final int start, final int length) { - if (cs instanceof String && substring instanceof String) { - return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length); - } - int index1 = thisStart; - int index2 = start; - int tmpLen = length; - - // Extract these first so we detect NPEs the same as the java.lang.String - // version - final int srcLen = cs.length() - thisStart; - final int otherLen = substring.length() - start; - - // Check for invalid parameters - if (thisStart < 0 || start < 0 || length < 0) { - return false; - } - - // Check that the regions are long enough - if (srcLen < length || otherLen < length) { - return false; - } - - while (tmpLen-- > 0) { - final char c1 = cs.charAt(index1++); - final char c2 = substring.charAt(index2++); - - if (c1 == c2) { - continue; - } - - if (!ignoreCase) { - return false; - } - - // The real same check as in String.regionMatches(): - final char u1 = Character.toUpperCase(c1); - final char u2 = Character.toUpperCase(c2); - if (u1 != u2 && Character.toLowerCase(u1) != Character.toLowerCase(u2)) { - return false; - } - } - - return true; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/CharSet.java b/sources/main/java/org/apache/commons/lang3/CharSet.java deleted file mode 100644 index 04a9ca91..00000000 --- a/sources/main/java/org/apache/commons/lang3/CharSet.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.io.Serializable; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - *

- * A set of characters. - *

- * - *

- * Instances are immutable, but instances of subclasses may not be. - *

- * - *

- * #ThreadSafe# - *

- * - * @since 1.0 - */ -public class CharSet implements Serializable { - - /** - * Required for serialization support. Lang version 2.0. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 5947847346149275958L; - - /** - * A CharSet defining no characters. - * - * @since 2.0 - */ - public static final CharSet EMPTY = new CharSet((String) null); - - /** - * A CharSet defining ASCII alphabetic characters "a-zA-Z". - * - * @since 2.0 - */ - public static final CharSet ASCII_ALPHA = new CharSet("a-zA-Z"); - - /** - * A CharSet defining ASCII alphabetic characters "a-z". - * - * @since 2.0 - */ - public static final CharSet ASCII_ALPHA_LOWER = new CharSet("a-z"); - - /** - * A CharSet defining ASCII alphabetic characters "A-Z". - * - * @since 2.0 - */ - public static final CharSet ASCII_ALPHA_UPPER = new CharSet("A-Z"); - - /** - * A CharSet defining ASCII alphabetic characters "0-9". - * - * @since 2.0 - */ - public static final CharSet ASCII_NUMERIC = new CharSet("0-9"); - - /** - * A Map of the common cases used in the factory. Subclasses can add more common - * patterns if desired - * - * @since 2.0 - */ - protected static final Map COMMON = Collections.synchronizedMap(new HashMap<>()); - - static { - COMMON.put(null, EMPTY); - COMMON.put(StringUtils.EMPTY, EMPTY); - COMMON.put("a-zA-Z", ASCII_ALPHA); - COMMON.put("A-Za-z", ASCII_ALPHA); - COMMON.put("a-z", ASCII_ALPHA_LOWER); - COMMON.put("A-Z", ASCII_ALPHA_UPPER); - COMMON.put("0-9", ASCII_NUMERIC); - } - - /** The set of CharRange objects. */ - private final Set set = Collections.synchronizedSet(new HashSet<>()); - - // ----------------------------------------------------------------------- - /** - *

- * Factory method to create a new CharSet using a special syntax. - *

- * - *
    - *
  • {@code null} or empty string ("") - set containing no characters
  • - *
  • Single character, such as "a" - set containing just that character
  • - *
  • Multi character, such as "a-e" - set containing characters from one - * character to the other
  • - *
  • Negated, such as "^a" or "^a-e" - set containing all characters except - * those defined
  • - *
  • Combinations, such as "abe-g" - set containing all the characters from - * the individual sets
  • - *
- * - *

- * The matching order is: - *

- *
    - *
  1. Negated multi character range, such as "^a-e" - *
  2. Ordinary multi character range, such as "a-e" - *
  3. Negated single character, such as "^a" - *
  4. Ordinary single character, such as "a" - *
- * - *

- * Matching works left to right. Once a match is found the search starts again - * from the next character. - *

- * - *

- * If the same range is defined twice using the same syntax, only one range will - * be kept. Thus, "a-ca-c" creates only one range of "a-c". - *

- * - *

- * If the start and end of a range are in the wrong order, they are reversed. - * Thus "a-e" is the same as "e-a". As a result, "a-ee-a" would create only one - * range, as the "a-e" and "e-a" are the same. - *

- * - *

- * The set of characters represented is the union of the specified ranges. - *

- * - *

- * There are two ways to add a literal negation character ({@code ^}): - *

- *
    - *
  • As the last character in a string, e.g. - * {@code CharSet.getInstance("a-z^")}
  • - *
  • As a separate element, e.g. {@code CharSet.getInstance("^", "a-z")}
  • - *
- * - *

- * Examples using the negation character: - *

- * - *
-	 *     CharSet.getInstance("^a-c").contains('a') = false
-	 *     CharSet.getInstance("^a-c").contains('d') = true
-	 *     CharSet.getInstance("^^a-c").contains('a') = true // (only '^' is negated)
-	 *     CharSet.getInstance("^^a-c").contains('^') = false
-	 *     CharSet.getInstance("^a-cd-f").contains('d') = true
-	 *     CharSet.getInstance("a-c^").contains('^') = true
-	 *     CharSet.getInstance("^", "a-c").contains('^') = true
-	 * 
- * - *

- * All CharSet objects returned by this method will be immutable. - *

- * - * @param setStrs Strings to merge into the set, may be null - * @return a CharSet instance - * @since 2.4 - */ - public static CharSet getInstance(final String... setStrs) { - if (setStrs == null) { - return null; - } - if (setStrs.length == 1) { - final CharSet common = COMMON.get(setStrs[0]); - if (common != null) { - return common; - } - } - return new CharSet(setStrs); - } - - // ----------------------------------------------------------------------- - /** - *

- * Constructs a new CharSet using the set syntax. Each string is merged in with - * the set. - *

- * - * @param set Strings to merge into the initial set - * @throws NullPointerException if set is {@code null} - */ - protected CharSet(final String... set) { - for (final String s : set) { - add(s); - } - } - - // ----------------------------------------------------------------------- - /** - *

- * Add a set definition string to the {@code CharSet}. - *

- * - * @param str set definition string - */ - protected void add(final String str) { - if (str == null) { - return; - } - - final int len = str.length(); - int pos = 0; - while (pos < len) { - final int remainder = len - pos; - if (remainder >= 4 && str.charAt(pos) == '^' && str.charAt(pos + 2) == '-') { - // negated range - set.add(CharRange.isNotIn(str.charAt(pos + 1), str.charAt(pos + 3))); - pos += 4; - } else if (remainder >= 3 && str.charAt(pos + 1) == '-') { - // range - set.add(CharRange.isIn(str.charAt(pos), str.charAt(pos + 2))); - pos += 3; - } else if (remainder >= 2 && str.charAt(pos) == '^') { - // negated char - set.add(CharRange.isNot(str.charAt(pos + 1))); - pos += 2; - } else { - // char - set.add(CharRange.is(str.charAt(pos))); - pos += 1; - } - } - } - - // ----------------------------------------------------------------------- - /** - *

- * Gets the internal set as an array of CharRange objects. - *

- * - * @return an array of immutable CharRange objects - * @since 2.0 - */ -// NOTE: This is no longer public as CharRange is no longer a public class. -// It may be replaced when CharSet moves to Range. - /* public */ CharRange[] getCharRanges() { - return set.toArray(CharRange.EMPTY_ARRAY); - } - - // ----------------------------------------------------------------------- - /** - *

- * Does the {@code CharSet} contain the specified character {@code ch}. - *

- * - * @param ch the character to check for - * @return {@code true} if the set contains the characters - */ - public boolean contains(final char ch) { - synchronized (set) { - for (final CharRange range : set) { - if (range.contains(ch)) { - return true; - } - } - } - return false; - } - - // Basics - // ----------------------------------------------------------------------- - /** - *

- * Compares two {@code CharSet} objects, returning true if they represent - * exactly the same set of characters defined in the same way. - *

- * - *

- * The two sets {@code abc} and {@code a-c} are not equal according to - * this method. - *

- * - * @param obj the object to compare to - * @return true if equal - * @since 2.0 - */ - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof CharSet)) { - return false; - } - final CharSet other = (CharSet) obj; - return set.equals(other.set); - } - - /** - *

- * Gets a hash code compatible with the equals method. - *

- * - * @return a suitable hash code - * @since 2.0 - */ - @Override - public int hashCode() { - return 89 + set.hashCode(); - } - - /** - *

- * Gets a string representation of the set. - *

- * - * @return string representation of the set - */ - @Override - public String toString() { - return set.toString(); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/CharSetUtils.java b/sources/main/java/org/apache/commons/lang3/CharSetUtils.java deleted file mode 100644 index dbadd761..00000000 --- a/sources/main/java/org/apache/commons/lang3/CharSetUtils.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -/** - *

- * Operations on {@code CharSet} instances. - *

- * - *

- * This class handles {@code null} input gracefully. An exception will not be - * thrown for a {@code null} input. Each method documents its behavior in more - * detail. - *

- * - *

- * #ThreadSafe# - *

- * - * @see CharSet - * @since 1.0 - */ -public class CharSetUtils { - - /** - *

- * Takes an argument in set-syntax, see evaluateSet, and identifies whether any - * of the characters are present in the specified string. - *

- * - *
-	 * CharSetUtils.containsAny(null, *)        = false
-	 * CharSetUtils.containsAny("", *)          = false
-	 * CharSetUtils.containsAny(*, null)        = false
-	 * CharSetUtils.containsAny(*, "")          = false
-	 * CharSetUtils.containsAny("hello", "k-p") = true
-	 * CharSetUtils.containsAny("hello", "a-d") = false
-	 * 
- * - * @see CharSet#getInstance(java.lang.String...) for set-syntax. - * @param str String to look for characters in, may be null - * @param set String[] set of characters to identify, may be null - * @return whether or not the characters in the set are in the primary string - * @since 3.2 - */ - public static boolean containsAny(final String str, final String... set) { - if (StringUtils.isEmpty(str) || deepEmpty(set)) { - return false; - } - final CharSet chars = CharSet.getInstance(set); - for (final char c : str.toCharArray()) { - if (chars.contains(c)) { - return true; - } - } - return false; - } - - /** - *

- * Takes an argument in set-syntax, see evaluateSet, and returns the number of - * characters present in the specified string. - *

- * - *
-	 * CharSetUtils.count(null, *)        = 0
-	 * CharSetUtils.count("", *)          = 0
-	 * CharSetUtils.count(*, null)        = 0
-	 * CharSetUtils.count(*, "")          = 0
-	 * CharSetUtils.count("hello", "k-p") = 3
-	 * CharSetUtils.count("hello", "a-e") = 1
-	 * 
- * - * @see CharSet#getInstance(java.lang.String...) for set-syntax. - * @param str String to count characters in, may be null - * @param set String[] set of characters to count, may be null - * @return the character count, zero if null string input - */ - public static int count(final String str, final String... set) { - if (StringUtils.isEmpty(str) || deepEmpty(set)) { - return 0; - } - final CharSet chars = CharSet.getInstance(set); - int count = 0; - for (final char c : str.toCharArray()) { - if (chars.contains(c)) { - count++; - } - } - return count; - } - - /** - * Determines whether or not all the Strings in an array are empty or not. - * - * @param strings String[] whose elements are being checked for emptiness - * @return whether or not the String is empty - */ - private static boolean deepEmpty(final String[] strings) { - if (strings != null) { - for (final String s : strings) { - if (StringUtils.isNotEmpty(s)) { - return false; - } - } - } - return true; - } - - /** - *

- * Takes an argument in set-syntax, see evaluateSet, and deletes any of - * characters present in the specified string. - *

- * - *
-	 * CharSetUtils.delete(null, *)        = null
-	 * CharSetUtils.delete("", *)          = ""
-	 * CharSetUtils.delete(*, null)        = *
-	 * CharSetUtils.delete(*, "")          = *
-	 * CharSetUtils.delete("hello", "hl")  = "eo"
-	 * CharSetUtils.delete("hello", "le")  = "ho"
-	 * 
- * - * @see CharSet#getInstance(java.lang.String...) for set-syntax. - * @param str String to delete characters from, may be null - * @param set String[] set of characters to delete, may be null - * @return the modified String, {@code null} if null string input - */ - public static String delete(final String str, final String... set) { - if (StringUtils.isEmpty(str) || deepEmpty(set)) { - return str; - } - return modify(str, set, false); - } - - /** - *

- * Takes an argument in set-syntax, see evaluateSet, and keeps any of characters - * present in the specified string. - *

- * - *
-	 * CharSetUtils.keep(null, *)        = null
-	 * CharSetUtils.keep("", *)          = ""
-	 * CharSetUtils.keep(*, null)        = ""
-	 * CharSetUtils.keep(*, "")          = ""
-	 * CharSetUtils.keep("hello", "hl")  = "hll"
-	 * CharSetUtils.keep("hello", "le")  = "ell"
-	 * 
- * - * @see CharSet#getInstance(java.lang.String...) for set-syntax. - * @param str String to keep characters from, may be null - * @param set String[] set of characters to keep, may be null - * @return the modified String, {@code null} if null string input - * @since 2.0 - */ - public static String keep(final String str, final String... set) { - if (str == null) { - return null; - } - if (str.isEmpty() || deepEmpty(set)) { - return StringUtils.EMPTY; - } - return modify(str, set, true); - } - - /** - * Implementation of delete and keep - * - * @param str String to modify characters within - * @param set String[] set of characters to modify - * @param expect whether to evaluate on match, or non-match - * @return the modified String, not null - */ - private static String modify(final String str, final String[] set, final boolean expect) { - final CharSet chars = CharSet.getInstance(set); - final StringBuilder buffer = new StringBuilder(str.length()); - final char[] chrs = str.toCharArray(); - for (final char chr : chrs) { - if (chars.contains(chr) == expect) { - buffer.append(chr); - } - } - return buffer.toString(); - } - - /** - *

- * Squeezes any repetitions of a character that is mentioned in the supplied - * set. - *

- * - *
-	 * CharSetUtils.squeeze(null, *)        = null
-	 * CharSetUtils.squeeze("", *)          = ""
-	 * CharSetUtils.squeeze(*, null)        = *
-	 * CharSetUtils.squeeze(*, "")          = *
-	 * CharSetUtils.squeeze("hello", "k-p") = "helo"
-	 * CharSetUtils.squeeze("hello", "a-e") = "hello"
-	 * 
- * - * @see CharSet#getInstance(java.lang.String...) for set-syntax. - * @param str the string to squeeze, may be null - * @param set the character set to use for manipulation, may be null - * @return the modified String, {@code null} if null string input - */ - public static String squeeze(final String str, final String... set) { - if (StringUtils.isEmpty(str) || deepEmpty(set)) { - return str; - } - final CharSet chars = CharSet.getInstance(set); - final StringBuilder buffer = new StringBuilder(str.length()); - final char[] chrs = str.toCharArray(); - final int sz = chrs.length; - char lastChar = chrs[0]; - char ch = ' '; - Character inChars = null; - Character notInChars = null; - buffer.append(lastChar); - for (int i = 1; i < sz; i++) { - ch = chrs[i]; - if (ch == lastChar) { - if (inChars != null && ch == inChars) { - continue; - } - if (notInChars == null || ch != notInChars) { - if (chars.contains(ch)) { - inChars = ch; - continue; - } - notInChars = ch; - } - } - buffer.append(ch); - lastChar = ch; - } - return buffer.toString(); - } - - /** - *

- * CharSetUtils instances should NOT be constructed in standard programming. - * Instead, the class should be used as {@code CharSetUtils.evaluateSet(null);}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public CharSetUtils() { - } -} diff --git a/sources/main/java/org/apache/commons/lang3/CharUtils.java b/sources/main/java/org/apache/commons/lang3/CharUtils.java deleted file mode 100644 index 93180cb4..00000000 --- a/sources/main/java/org/apache/commons/lang3/CharUtils.java +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -/** - *

- * Operations on char primitives and Character objects. - *

- * - *

- * This class tries to handle {@code null} input gracefully. An exception will - * not be thrown for a {@code null} input. Each method documents its behavior in - * more detail. - *

- * - *

- * #ThreadSafe# - *

- * - * @since 2.1 - */ -public class CharUtils { - - private static final String[] CHAR_STRING_ARRAY = new String[128]; - - private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', - 'e', 'f' }; - - /** - * Linefeed character LF ({@code '\n'}, Unicode 000a). - * - * @see JLF: - * Escape Sequences for Character and String Literals - * @since 2.2 - */ - public static final char LF = '\n'; - - /** - * Carriage return characterf CR ('\r', Unicode 000d). - * - * @see JLF: - * Escape Sequences for Character and String Literals - * @since 2.2 - */ - public static final char CR = '\r'; - - /** - * {@code \u0000} null control character ('\0'), abbreviated NUL. - * - * @since 3.6 - */ - public static final char NUL = '\0'; - - static { - for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) { - CHAR_STRING_ARRAY[c] = String.valueOf(c); - } - } - - /** - *

- * {@code CharUtils} instances should NOT be constructed in standard - * programming. Instead, the class should be used as - * {@code CharUtils.toString('c');}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public CharUtils() { - } - - // ----------------------------------------------------------------------- - /** - *

- * Converts the character to a Character. - *

- * - *

- * For ASCII 7 bit characters, this uses a cache that will return the same - * Character object each time. - *

- * - *
-	 *   CharUtils.toCharacterObject(' ')  = ' '
-	 *   CharUtils.toCharacterObject('A')  = 'A'
-	 * 
- * - * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches - * chars 0 through 127. - * @param ch the character to convert - * @return a Character of the specified character - */ - @Deprecated - public static Character toCharacterObject(final char ch) { - return Character.valueOf(ch); - } - - /** - *

- * Converts the String to a Character using the first character, returning null - * for empty Strings. - *

- * - *

- * For ASCII 7 bit characters, this uses a cache that will return the same - * Character object each time. - *

- * - *
-	 *   CharUtils.toCharacterObject(null) = null
-	 *   CharUtils.toCharacterObject("")   = null
-	 *   CharUtils.toCharacterObject("A")  = 'A'
-	 *   CharUtils.toCharacterObject("BA") = 'B'
-	 * 
- * - * @param str the character to convert - * @return the Character value of the first letter of the String - */ - public static Character toCharacterObject(final String str) { - if (StringUtils.isEmpty(str)) { - return null; - } - return Character.valueOf(str.charAt(0)); - } - - // ----------------------------------------------------------------------- - /** - *

- * Converts the Character to a char throwing an exception for {@code null}. - *

- * - *
-	 *   CharUtils.toChar(' ')  = ' '
-	 *   CharUtils.toChar('A')  = 'A'
-	 *   CharUtils.toChar(null) throws IllegalArgumentException
-	 * 
- * - * @param ch the character to convert - * @return the char value of the Character - * @throws NullPointerException if the Character is null - */ - public static char toChar(final Character ch) { - Validate.notNull(ch, "ch"); - return ch.charValue(); - } - - /** - *

- * Converts the Character to a char handling {@code null}. - *

- * - *
-	 *   CharUtils.toChar(null, 'X') = 'X'
-	 *   CharUtils.toChar(' ', 'X')  = ' '
-	 *   CharUtils.toChar('A', 'X')  = 'A'
-	 * 
- * - * @param ch the character to convert - * @param defaultValue the value to use if the Character is null - * @return the char value of the Character or the default if null - */ - public static char toChar(final Character ch, final char defaultValue) { - if (ch == null) { - return defaultValue; - } - return ch.charValue(); - } - - // ----------------------------------------------------------------------- - /** - *

- * Converts the String to a char using the first character, throwing an - * exception on empty Strings. - *

- * - *
-	 *   CharUtils.toChar("A")  = 'A'
-	 *   CharUtils.toChar("BA") = 'B'
-	 *   CharUtils.toChar(null) throws IllegalArgumentException
-	 *   CharUtils.toChar("")   throws IllegalArgumentException
-	 * 
- * - * @param str the character to convert - * @return the char value of the first letter of the String - * @throws NullPointerException if the string is null - * @throws IllegalArgumentException if the String is empty - */ - public static char toChar(final String str) { - Validate.notEmpty(str, "The String must not be empty"); - return str.charAt(0); - } - - /** - *

- * Converts the String to a char using the first character, defaulting the value - * on empty Strings. - *

- * - *
-	 *   CharUtils.toChar(null, 'X') = 'X'
-	 *   CharUtils.toChar("", 'X')   = 'X'
-	 *   CharUtils.toChar("A", 'X')  = 'A'
-	 *   CharUtils.toChar("BA", 'X') = 'B'
-	 * 
- * - * @param str the character to convert - * @param defaultValue the value to use if the Character is null - * @return the char value of the first letter of the String or the default if - * null - */ - public static char toChar(final String str, final char defaultValue) { - if (StringUtils.isEmpty(str)) { - return defaultValue; - } - return str.charAt(0); - } - - // ----------------------------------------------------------------------- - /** - *

- * Converts the character to the Integer it represents, throwing an exception if - * the character is not numeric. - *

- * - *

- * This method converts the char '1' to the int 1 and so on. - *

- * - *
-	 *   CharUtils.toIntValue('3')  = 3
-	 *   CharUtils.toIntValue('A')  throws IllegalArgumentException
-	 * 
- * - * @param ch the character to convert - * @return the int value of the character - * @throws IllegalArgumentException if the character is not ASCII numeric - */ - public static int toIntValue(final char ch) { - if (!isAsciiNumeric(ch)) { - throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'"); - } - return ch - 48; - } - - /** - *

- * Converts the character to the Integer it represents, throwing an exception if - * the character is not numeric. - *

- * - *

- * This method converts the char '1' to the int 1 and so on. - *

- * - *
-	 *   CharUtils.toIntValue('3', -1)  = 3
-	 *   CharUtils.toIntValue('A', -1)  = -1
-	 * 
- * - * @param ch the character to convert - * @param defaultValue the default value to use if the character is not numeric - * @return the int value of the character - */ - public static int toIntValue(final char ch, final int defaultValue) { - if (!isAsciiNumeric(ch)) { - return defaultValue; - } - return ch - 48; - } - - /** - *

- * Converts the character to the Integer it represents, throwing an exception if - * the character is not numeric. - *

- * - *

- * This method converts the char '1' to the int 1 and so on. - *

- * - *
-	 *   CharUtils.toIntValue('3')  = 3
-	 *   CharUtils.toIntValue(null) throws IllegalArgumentException
-	 *   CharUtils.toIntValue('A')  throws IllegalArgumentException
-	 * 
- * - * @param ch the character to convert, not null - * @return the int value of the character - * @throws NullPointerException if the Character is null - * @throws IllegalArgumentException if the Character is not ASCII numeric - */ - public static int toIntValue(final Character ch) { - Validate.notNull(ch, "ch"); - return toIntValue(ch.charValue()); - } - - /** - *

- * Converts the character to the Integer it represents, throwing an exception if - * the character is not numeric. - *

- * - *

- * This method converts the char '1' to the int 1 and so on. - *

- * - *
-	 *   CharUtils.toIntValue(null, -1) = -1
-	 *   CharUtils.toIntValue('3', -1)  = 3
-	 *   CharUtils.toIntValue('A', -1)  = -1
-	 * 
- * - * @param ch the character to convert - * @param defaultValue the default value to use if the character is not numeric - * @return the int value of the character - */ - public static int toIntValue(final Character ch, final int defaultValue) { - if (ch == null) { - return defaultValue; - } - return toIntValue(ch.charValue(), defaultValue); - } - - // ----------------------------------------------------------------------- - /** - *

- * Converts the character to a String that contains the one character. - *

- * - *

- * For ASCII 7 bit characters, this uses a cache that will return the same - * String object each time. - *

- * - *
-	 *   CharUtils.toString(' ')  = " "
-	 *   CharUtils.toString('A')  = "A"
-	 * 
- * - * @param ch the character to convert - * @return a String containing the one specified character - */ - public static String toString(final char ch) { - if (ch < 128) { - return CHAR_STRING_ARRAY[ch]; - } - return new String(new char[] { ch }); - } - - /** - *

- * Converts the character to a String that contains the one character. - *

- * - *

- * For ASCII 7 bit characters, this uses a cache that will return the same - * String object each time. - *

- * - *

- * If {@code null} is passed in, {@code null} will be returned. - *

- * - *
-	 *   CharUtils.toString(null) = null
-	 *   CharUtils.toString(' ')  = " "
-	 *   CharUtils.toString('A')  = "A"
-	 * 
- * - * @param ch the character to convert - * @return a String containing the one specified character - */ - public static String toString(final Character ch) { - if (ch == null) { - return null; - } - return toString(ch.charValue()); - } - - // -------------------------------------------------------------------------- - /** - *

- * Converts the string to the Unicode format '\u0020'. - *

- * - *

- * This format is the Java source code format. - *

- * - *
-	 *   CharUtils.unicodeEscaped(' ') = "\u0020"
-	 *   CharUtils.unicodeEscaped('A') = "\u0041"
-	 * 
- * - * @param ch the character to convert - * @return the escaped Unicode string - */ - public static String unicodeEscaped(final char ch) { - return "\\u" + HEX_DIGITS[(ch >> 12) & 15] + HEX_DIGITS[(ch >> 8) & 15] + HEX_DIGITS[(ch >> 4) & 15] - + HEX_DIGITS[(ch) & 15]; - } - - /** - *

- * Converts the string to the Unicode format '\u0020'. - *

- * - *

- * This format is the Java source code format. - *

- * - *

- * If {@code null} is passed in, {@code null} will be returned. - *

- * - *
-	 *   CharUtils.unicodeEscaped(null) = null
-	 *   CharUtils.unicodeEscaped(' ')  = "\u0020"
-	 *   CharUtils.unicodeEscaped('A')  = "\u0041"
-	 * 
- * - * @param ch the character to convert, may be null - * @return the escaped Unicode string, null if null input - */ - public static String unicodeEscaped(final Character ch) { - if (ch == null) { - return null; - } - return unicodeEscaped(ch.charValue()); - } - - // -------------------------------------------------------------------------- - /** - *

- * Checks whether the character is ASCII 7 bit. - *

- * - *
-	 *   CharUtils.isAscii('a')  = true
-	 *   CharUtils.isAscii('A')  = true
-	 *   CharUtils.isAscii('3')  = true
-	 *   CharUtils.isAscii('-')  = true
-	 *   CharUtils.isAscii('\n') = true
-	 *   CharUtils.isAscii('©') = false
-	 * 
- * - * @param ch the character to check - * @return true if less than 128 - */ - public static boolean isAscii(final char ch) { - return ch < 128; - } - - /** - *

- * Checks whether the character is ASCII 7 bit printable. - *

- * - *
-	 *   CharUtils.isAsciiPrintable('a')  = true
-	 *   CharUtils.isAsciiPrintable('A')  = true
-	 *   CharUtils.isAsciiPrintable('3')  = true
-	 *   CharUtils.isAsciiPrintable('-')  = true
-	 *   CharUtils.isAsciiPrintable('\n') = false
-	 *   CharUtils.isAsciiPrintable('©') = false
-	 * 
- * - * @param ch the character to check - * @return true if between 32 and 126 inclusive - */ - public static boolean isAsciiPrintable(final char ch) { - return ch >= 32 && ch < 127; - } - - /** - *

- * Checks whether the character is ASCII 7 bit control. - *

- * - *
-	 *   CharUtils.isAsciiControl('a')  = false
-	 *   CharUtils.isAsciiControl('A')  = false
-	 *   CharUtils.isAsciiControl('3')  = false
-	 *   CharUtils.isAsciiControl('-')  = false
-	 *   CharUtils.isAsciiControl('\n') = true
-	 *   CharUtils.isAsciiControl('©') = false
-	 * 
- * - * @param ch the character to check - * @return true if less than 32 or equals 127 - */ - public static boolean isAsciiControl(final char ch) { - return ch < 32 || ch == 127; - } - - /** - *

- * Checks whether the character is ASCII 7 bit alphabetic. - *

- * - *
-	 *   CharUtils.isAsciiAlpha('a')  = true
-	 *   CharUtils.isAsciiAlpha('A')  = true
-	 *   CharUtils.isAsciiAlpha('3')  = false
-	 *   CharUtils.isAsciiAlpha('-')  = false
-	 *   CharUtils.isAsciiAlpha('\n') = false
-	 *   CharUtils.isAsciiAlpha('©') = false
-	 * 
- * - * @param ch the character to check - * @return true if between 65 and 90 or 97 and 122 inclusive - */ - public static boolean isAsciiAlpha(final char ch) { - return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch); - } - - /** - *

- * Checks whether the character is ASCII 7 bit alphabetic upper case. - *

- * - *
-	 *   CharUtils.isAsciiAlphaUpper('a')  = false
-	 *   CharUtils.isAsciiAlphaUpper('A')  = true
-	 *   CharUtils.isAsciiAlphaUpper('3')  = false
-	 *   CharUtils.isAsciiAlphaUpper('-')  = false
-	 *   CharUtils.isAsciiAlphaUpper('\n') = false
-	 *   CharUtils.isAsciiAlphaUpper('©') = false
-	 * 
- * - * @param ch the character to check - * @return true if between 65 and 90 inclusive - */ - public static boolean isAsciiAlphaUpper(final char ch) { - return ch >= 'A' && ch <= 'Z'; - } - - /** - *

- * Checks whether the character is ASCII 7 bit alphabetic lower case. - *

- * - *
-	 *   CharUtils.isAsciiAlphaLower('a')  = true
-	 *   CharUtils.isAsciiAlphaLower('A')  = false
-	 *   CharUtils.isAsciiAlphaLower('3')  = false
-	 *   CharUtils.isAsciiAlphaLower('-')  = false
-	 *   CharUtils.isAsciiAlphaLower('\n') = false
-	 *   CharUtils.isAsciiAlphaLower('©') = false
-	 * 
- * - * @param ch the character to check - * @return true if between 97 and 122 inclusive - */ - public static boolean isAsciiAlphaLower(final char ch) { - return ch >= 'a' && ch <= 'z'; - } - - /** - *

- * Checks whether the character is ASCII 7 bit numeric. - *

- * - *
-	 *   CharUtils.isAsciiNumeric('a')  = false
-	 *   CharUtils.isAsciiNumeric('A')  = false
-	 *   CharUtils.isAsciiNumeric('3')  = true
-	 *   CharUtils.isAsciiNumeric('-')  = false
-	 *   CharUtils.isAsciiNumeric('\n') = false
-	 *   CharUtils.isAsciiNumeric('©') = false
-	 * 
- * - * @param ch the character to check - * @return true if between 48 and 57 inclusive - */ - public static boolean isAsciiNumeric(final char ch) { - return ch >= '0' && ch <= '9'; - } - - /** - *

- * Checks whether the character is ASCII 7 bit numeric. - *

- * - *
-	 *   CharUtils.isAsciiAlphanumeric('a')  = true
-	 *   CharUtils.isAsciiAlphanumeric('A')  = true
-	 *   CharUtils.isAsciiAlphanumeric('3')  = true
-	 *   CharUtils.isAsciiAlphanumeric('-')  = false
-	 *   CharUtils.isAsciiAlphanumeric('\n') = false
-	 *   CharUtils.isAsciiAlphanumeric('©') = false
-	 * 
- * - * @param ch the character to check - * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive - */ - public static boolean isAsciiAlphanumeric(final char ch) { - return isAsciiAlpha(ch) || isAsciiNumeric(ch); - } - - /** - *

- * Compares two {@code char} values numerically. This is the same functionality - * as provided in Java 7. - *

- * - * @param x the first {@code char} to compare - * @param y the second {@code char} to compare - * @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if - * {@code x < y}; and a value greater than {@code 0} if {@code x > y} - * @since 3.4 - */ - public static int compare(final char x, final char y) { - return x - y; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/Charsets.java b/sources/main/java/org/apache/commons/lang3/Charsets.java deleted file mode 100644 index d7cd3021..00000000 --- a/sources/main/java/org/apache/commons/lang3/Charsets.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3; - -import java.nio.charset.Charset; -import java.nio.charset.UnsupportedCharsetException; - -/** - * Internal use only. - *

- * Provides utilities for {@link Charset}. - *

- *

- * Package private since Apache Commons IO already provides a Charsets because - * {@link Charset} is in {@code java.nio.charset}. - *

- * - * @since 3.10 - */ -class Charsets { - - /** - * Returns the given {@code charset} or the default Charset if {@code charset} - * is null. - * - * @param charset a Charset or null. - * @return the given {@code charset} or the default Charset if {@code charset} - * is null. - */ - static Charset toCharset(final Charset charset) { - return charset == null ? Charset.defaultCharset() : charset; - } - - /** - * Returns the given {@code charset} or the default Charset if {@code charset} - * is null. - * - * @param charsetName a Charset or null. - * @return the given {@code charset} or the default Charset if {@code charset} - * is null. - * @throws UnsupportedCharsetException If no support for the named charset is - * available in this instance of the Java - * virtual machine - */ - static Charset toCharset(final String charsetName) { - return charsetName == null ? Charset.defaultCharset() : Charset.forName(charsetName); - } - - /** - * Returns the given {@code charset} or the default Charset if {@code charset} - * is null. - * - * @param charsetName a Charset or null. - * @return the given {@code charset} or the default Charset if {@code charset} - * is null. - */ - static String toCharsetName(final String charsetName) { - return charsetName == null ? Charset.defaultCharset().name() : charsetName; - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/ClassLoaderUtils.java b/sources/main/java/org/apache/commons/lang3/ClassLoaderUtils.java deleted file mode 100644 index b4310623..00000000 --- a/sources/main/java/org/apache/commons/lang3/ClassLoaderUtils.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3; - -import java.net.URLClassLoader; -import java.util.Arrays; - -/** - * Helps work with {@link ClassLoader}. - * - * @since 3.10 - */ -public class ClassLoaderUtils { - - /** - * Converts the given class loader to a String calling - * {@link #toString(URLClassLoader)}. - * - * @param classLoader to URLClassLoader to convert. - * @return the formatted string. - */ - public static String toString(final ClassLoader classLoader) { - if (classLoader instanceof URLClassLoader) { - return toString((URLClassLoader) classLoader); - } - return classLoader.toString(); - } - - /** - * Converts the given URLClassLoader to a String in the format - * {@code "URLClassLoader.toString() + [URL1, URL2, ...]"}. - * - * @param classLoader to URLClassLoader to convert. - * @return the formatted string. - */ - public static String toString(final URLClassLoader classLoader) { - return classLoader + Arrays.toString(classLoader.getURLs()); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/ClassPathUtils.java b/sources/main/java/org/apache/commons/lang3/ClassPathUtils.java deleted file mode 100644 index ccee09d0..00000000 --- a/sources/main/java/org/apache/commons/lang3/ClassPathUtils.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -/** - * Operations regarding the classpath. - * - *

- * The methods of this class do not allow {@code null} inputs. - *

- * - * @since 3.3 - */ -//@Immutable -public class ClassPathUtils { - - /** - *

- * {@code ClassPathUtils} instances should NOT be constructed in standard - * programming. Instead, the class should be used as - * {@code ClassPathUtils.toFullyQualifiedName(MyClass.class, "MyClass.properties");}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public ClassPathUtils() { - } - - /** - * Returns the fully qualified name for the resource with name - * {@code resourceName} relative to the given context. - * - *

- * Note that this method does not check whether the resource actually exists. It - * only constructs the name. Null inputs are not allowed. - *

- * - *
-	 * ClassPathUtils.toFullyQualifiedName(StringUtils.class,
-	 * 		"StringUtils.properties") = "org.apache.commons.lang3.StringUtils.properties"
-	 * 
- * - * @param context The context for constructing the name. - * @param resourceName the resource name to construct the fully qualified name - * for. - * @return the fully qualified name of the resource with name - * {@code resourceName}. - * @throws java.lang.NullPointerException if either {@code context} or - * {@code resourceName} is null. - */ - public static String toFullyQualifiedName(final Class context, final String resourceName) { - Validate.notNull(context, "context"); - Validate.notNull(resourceName, "resourceName"); - return toFullyQualifiedName(context.getPackage(), resourceName); - } - - /** - * Returns the fully qualified name for the resource with name - * {@code resourceName} relative to the given context. - * - *

- * Note that this method does not check whether the resource actually exists. It - * only constructs the name. Null inputs are not allowed. - *

- * - *
-	 * ClassPathUtils.toFullyQualifiedName(StringUtils.class.getPackage(),
-	 * 		"StringUtils.properties") = "org.apache.commons.lang3.StringUtils.properties"
-	 * 
- * - * @param context The context for constructing the name. - * @param resourceName the resource name to construct the fully qualified name - * for. - * @return the fully qualified name of the resource with name - * {@code resourceName}. - * @throws java.lang.NullPointerException if either {@code context} or - * {@code resourceName} is null. - */ - public static String toFullyQualifiedName(final Package context, final String resourceName) { - Validate.notNull(context, "context"); - Validate.notNull(resourceName, "resourceName"); - return context.getName() + "." + resourceName; - } - - /** - * Returns the fully qualified path for the resource with name - * {@code resourceName} relative to the given context. - * - *

- * Note that this method does not check whether the resource actually exists. It - * only constructs the path. Null inputs are not allowed. - *

- * - *
-	 * ClassPathUtils.toFullyQualifiedPath(StringUtils.class,
-	 * 		"StringUtils.properties") = "org/apache/commons/lang3/StringUtils.properties"
-	 * 
- * - * @param context The context for constructing the path. - * @param resourceName the resource name to construct the fully qualified path - * for. - * @return the fully qualified path of the resource with name - * {@code resourceName}. - * @throws java.lang.NullPointerException if either {@code context} or - * {@code resourceName} is null. - */ - public static String toFullyQualifiedPath(final Class context, final String resourceName) { - Validate.notNull(context, "context"); - Validate.notNull(resourceName, "resourceName"); - return toFullyQualifiedPath(context.getPackage(), resourceName); - } - - /** - * Returns the fully qualified path for the resource with name - * {@code resourceName} relative to the given context. - * - *

- * Note that this method does not check whether the resource actually exists. It - * only constructs the path. Null inputs are not allowed. - *

- * - *
-	 * ClassPathUtils.toFullyQualifiedPath(StringUtils.class.getPackage(),
-	 * 		"StringUtils.properties") = "org/apache/commons/lang3/StringUtils.properties"
-	 * 
- * - * @param context The context for constructing the path. - * @param resourceName the resource name to construct the fully qualified path - * for. - * @return the fully qualified path of the resource with name - * {@code resourceName}. - * @throws java.lang.NullPointerException if either {@code context} or - * {@code resourceName} is null. - */ - public static String toFullyQualifiedPath(final Package context, final String resourceName) { - Validate.notNull(context, "context"); - Validate.notNull(resourceName, "resourceName"); - return context.getName().replace('.', '/') + "/" + resourceName; - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/Conversion.java b/sources/main/java/org/apache/commons/lang3/Conversion.java deleted file mode 100644 index 30965383..00000000 --- a/sources/main/java/org/apache/commons/lang3/Conversion.java +++ /dev/null @@ -1,1610 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; - -/** - *

- * Static methods to convert a type into another, with endianness and bit - * ordering awareness. - *

- *

- * The methods names follow a naming rule:
- * {@code [source endianness][source bit ordering]To[destination endianness][destination bit ordering]} - *

- *

- * Source/destination type fields is one of the following: - *

- *
    - *
  • binary: an array of booleans
  • - *
  • byte or byteArray
  • - *
  • int or intArray
  • - *
  • long or longArray
  • - *
  • hex: a String containing hexadecimal digits (lowercase in - * destination)
  • - *
  • hexDigit: a Char containing a hexadecimal digit (lowercase in - * destination)
  • - *
  • uuid
  • - *
- *

- * Endianness field: little endian is the default, in this case the field is - * absent. In case of big endian, the field is "Be".
- * Bit ordering: Lsb0 is the default, in this case the field is absent. In case - * of Msb0, the field is "Msb0". - *

- *

- * Example: intBeMsb0ToHex convert an int with big endian byte order and Msb0 - * bit order into its hexadecimal string representation - *

- *

- * Most of the methods provide only default encoding for destination, this - * limits the number of ways to do one thing. Unless you are dealing with data - * from/to outside of the JVM platform, you should not need to use "Be" and - * "Msb0" methods. - *

- *

- * Development status: work on going, only a part of the little endian, Lsb0 - * methods implemented so far. - *

- * - * @since 3.2 - */ - -public class Conversion { - - private static final boolean[] TTTT = { true, true, true, true }; - private static final boolean[] FTTT = { false, true, true, true }; - private static final boolean[] TFTT = { true, false, true, true }; - private static final boolean[] FFTT = { false, false, true, true }; - private static final boolean[] TTFT = { true, true, false, true }; - private static final boolean[] FTFT = { false, true, false, true }; - private static final boolean[] TFFT = { true, false, false, true }; - private static final boolean[] FFFT = { false, false, false, true }; - private static final boolean[] TTTF = { true, true, true, false }; - private static final boolean[] FTTF = { false, true, true, false }; - private static final boolean[] TFTF = { true, false, true, false }; - private static final boolean[] FFTF = { false, false, true, false }; - private static final boolean[] TTFF = { true, true, false, false }; - private static final boolean[] FTFF = { false, true, false, false }; - private static final boolean[] TFFF = { true, false, false, false }; - private static final boolean[] FFFF = { false, false, false, false }; - - /** - *

- * Converts a hexadecimal digit into an int using the default (Lsb0) bit - * ordering. - *

- *

- * '1' is converted to 1 - *

- * - * @param hexDigit the hexadecimal digit to convert - * @return an int equals to {@code hexDigit} - * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal - * digit - */ - public static int hexDigitToInt(final char hexDigit) { - final int digit = Character.digit(hexDigit, 16); - if (digit < 0) { - throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit"); - } - return digit; - } - - /** - *

- * Converts a hexadecimal digit into an int using the Msb0 bit ordering. - *

- *

- * '1' is converted to 8 - *

- * - * @param hexDigit the hexadecimal digit to convert - * @return an int equals to {@code hexDigit} - * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal - * digit - */ - public static int hexDigitMsb0ToInt(final char hexDigit) { - switch (hexDigit) { - case '0': - return 0x0; - case '1': - return 0x8; - case '2': - return 0x4; - case '3': - return 0xC; - case '4': - return 0x2; - case '5': - return 0xA; - case '6': - return 0x6; - case '7': - return 0xE; - case '8': - return 0x1; - case '9': - return 0x9; - case 'a':// fall through - case 'A': - return 0x5; - case 'b':// fall through - case 'B': - return 0xD; - case 'c':// fall through - case 'C': - return 0x3; - case 'd':// fall through - case 'D': - return 0xB; - case 'e':// fall through - case 'E': - return 0x7; - case 'f':// fall through - case 'F': - return 0xF; - default: - throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit"); - } - } - - /** - *

- * Converts a hexadecimal digit into binary (represented as boolean array) using - * the default (Lsb0) bit ordering. - *

- *

- * '1' is converted as follow: (1, 0, 0, 0) - *

- * - * @param hexDigit the hexadecimal digit to convert - * @return a boolean array with the binary representation of {@code hexDigit} - * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal - * digit - */ - public static boolean[] hexDigitToBinary(final char hexDigit) { - switch (hexDigit) { - case '0': - return FFFF.clone(); - case '1': - return TFFF.clone(); - case '2': - return FTFF.clone(); - case '3': - return TTFF.clone(); - case '4': - return FFTF.clone(); - case '5': - return TFTF.clone(); - case '6': - return FTTF.clone(); - case '7': - return TTTF.clone(); - case '8': - return FFFT.clone(); - case '9': - return TFFT.clone(); - case 'a':// fall through - case 'A': - return FTFT.clone(); - case 'b':// fall through - case 'B': - return TTFT.clone(); - case 'c':// fall through - case 'C': - return FFTT.clone(); - case 'd':// fall through - case 'D': - return TFTT.clone(); - case 'e':// fall through - case 'E': - return FTTT.clone(); - case 'f':// fall through - case 'F': - return TTTT.clone(); - default: - throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit"); - } - } - - /** - *

- * Converts a hexadecimal digit into binary (represented as boolean array) using - * the Msb0 bit ordering. - *

- *

- * '1' is converted as follow: (0, 0, 0, 1) - *

- * - * @param hexDigit the hexadecimal digit to convert - * @return a boolean array with the binary representation of {@code hexDigit} - * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal - * digit - */ - public static boolean[] hexDigitMsb0ToBinary(final char hexDigit) { - switch (hexDigit) { - case '0': - return FFFF.clone(); - case '1': - return FFFT.clone(); - case '2': - return FFTF.clone(); - case '3': - return FFTT.clone(); - case '4': - return FTFF.clone(); - case '5': - return FTFT.clone(); - case '6': - return FTTF.clone(); - case '7': - return FTTT.clone(); - case '8': - return TFFF.clone(); - case '9': - return TFFT.clone(); - case 'a':// fall through - case 'A': - return TFTF.clone(); - case 'b':// fall through - case 'B': - return TFTT.clone(); - case 'c':// fall through - case 'C': - return TTFF.clone(); - case 'd':// fall through - case 'D': - return TTFT.clone(); - case 'e':// fall through - case 'E': - return TTTF.clone(); - case 'f':// fall through - case 'F': - return TTTT.clone(); - default: - throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit"); - } - } - - /** - *

- * Converts binary (represented as boolean array) to a hexadecimal digit using - * the default (Lsb0) bit ordering. - *

- *

- * (1, 0, 0, 0) is converted as follow: '1' - *

- * - * @param src the binary to convert - * @return a hexadecimal digit representing the selected bits - * @throws IllegalArgumentException if {@code src} is empty - * @throws NullPointerException if {@code src} is {@code null} - */ - public static char binaryToHexDigit(final boolean[] src) { - return binaryToHexDigit(src, 0); - } - - /** - *

- * Converts binary (represented as boolean array) to a hexadecimal digit using - * the default (Lsb0) bit ordering. - *

- *

- * (1, 0, 0, 0) is converted as follow: '1' - *

- * - * @param src the binary to convert - * @param srcPos the position of the lsb to start the conversion - * @return a hexadecimal digit representing the selected bits - * @throws IllegalArgumentException if {@code src} is empty - * @throws NullPointerException if {@code src} is {@code null} - */ - public static char binaryToHexDigit(final boolean[] src, final int srcPos) { - if (src.length == 0) { - throw new IllegalArgumentException("Cannot convert an empty array."); - } - if (src.length > srcPos + 3 && src[srcPos + 3]) { - if (src[srcPos + 2]) { - if (src[srcPos + 1]) { - return src[srcPos] ? 'f' : 'e'; - } - return src[srcPos] ? 'd' : 'c'; - } - if (src[srcPos + 1]) { - return src[srcPos] ? 'b' : 'a'; - } - return src[srcPos] ? '9' : '8'; - } - if (src.length > srcPos + 2 && src[srcPos + 2]) { - if (src[srcPos + 1]) { - return src[srcPos] ? '7' : '6'; - } - return src[srcPos] ? '5' : '4'; - } - if (src.length > srcPos + 1 && src[srcPos + 1]) { - return src[srcPos] ? '3' : '2'; - } - return src[srcPos] ? '1' : '0'; - } - - /** - *

- * Converts binary (represented as boolean array) to a hexadecimal digit using - * the Msb0 bit ordering. - *

- *

- * (1, 0, 0, 0) is converted as follow: '8' - *

- * - * @param src the binary to convert - * @return a hexadecimal digit representing the selected bits - * @throws IllegalArgumentException if {@code src} is empty, - * {@code src.length < 4} or - * {@code src.length > 8} - * @throws NullPointerException if {@code src} is {@code null} - */ - public static char binaryToHexDigitMsb0_4bits(final boolean[] src) { - return binaryToHexDigitMsb0_4bits(src, 0); - } - - /** - *

- * Converts binary (represented as boolean array) to a hexadecimal digit using - * the Msb0 bit ordering. - *

- *

- * (1, 0, 0, 0) is converted as follow: '8' (1, 0, 0, 1, 1, 0, 1, 0) with srcPos - * = 3 is converted to 'D' - *

- * - * @param src the binary to convert - * @param srcPos the position of the lsb to start the conversion - * @return a hexadecimal digit representing the selected bits - * @throws IllegalArgumentException if {@code src} is empty, - * {@code src.length > 8} or - * {@code src.length - srcPos < 4} - * @throws NullPointerException if {@code src} is {@code null} - */ - public static char binaryToHexDigitMsb0_4bits(final boolean[] src, final int srcPos) { - if (src.length > 8) { - throw new IllegalArgumentException("src.length>8: src.length=" + src.length); - } - if (src.length - srcPos < 4) { - throw new IllegalArgumentException("src.length-srcPos<4: src.length=" + src.length + ", srcPos=" + srcPos); - } - if (src[srcPos + 3]) { - if (src[srcPos + 2]) { - if (src[srcPos + 1]) { - return src[srcPos] ? 'f' : '7'; - } - return src[srcPos] ? 'b' : '3'; - } - if (src[srcPos + 1]) { - return src[srcPos] ? 'd' : '5'; - } - return src[srcPos] ? '9' : '1'; - } - if (src[srcPos + 2]) { - if (src[srcPos + 1]) { - return src[srcPos] ? 'e' : '6'; - } - return src[srcPos] ? 'a' : '2'; - } - if (src[srcPos + 1]) { - return src[srcPos] ? 'c' : '4'; - } - return src[srcPos] ? '8' : '0'; - } - - /** - *

- * Converts the first 4 bits of a binary (represented as boolean array) in big - * endian Msb0 bit ordering to a hexadecimal digit. - *

- *

- * (1, 0, 0, 0) is converted as follow: '8' (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - * 0, 1, 0, 0) is converted to '4' - *

- * - * @param src the binary to convert - * @return a hexadecimal digit representing the selected bits - * @throws IllegalArgumentException if {@code src} is empty - * @throws NullPointerException if {@code src} is {@code null} - */ - public static char binaryBeMsb0ToHexDigit(final boolean[] src) { - return binaryBeMsb0ToHexDigit(src, 0); - } - - /** - *

- * Converts a binary (represented as boolean array) in big endian Msb0 bit - * ordering to a hexadecimal digit. - *

- *

- * (1, 0, 0, 0) with srcPos = 0 is converted as follow: '8' (1, 0, 0, 0, 0, 0, - * 0, 0, 0, 0, 0, 1, 0, 1, 0, 0) with srcPos = 2 is converted to '5' - *

- * - * @param src the binary to convert - * @param srcPos the position of the lsb to start the conversion - * @return a hexadecimal digit representing the selected bits - * @throws IllegalArgumentException if {@code src} is empty - * @throws NullPointerException if {@code src} is {@code null} - */ - public static char binaryBeMsb0ToHexDigit(boolean[] src, int srcPos) { - if (src.length == 0) { - throw new IllegalArgumentException("Cannot convert an empty array."); - } - final int beSrcPos = src.length - 1 - srcPos; - final int srcLen = Math.min(4, beSrcPos + 1); - final boolean[] paddedSrc = new boolean[4]; - System.arraycopy(src, beSrcPos + 1 - srcLen, paddedSrc, 4 - srcLen, srcLen); - src = paddedSrc; - srcPos = 0; - if (src[srcPos]) { - if (src.length > srcPos + 1 && src[srcPos + 1]) { - if (src.length > srcPos + 2 && src[srcPos + 2]) { - return src.length > srcPos + 3 && src[srcPos + 3] ? 'f' : 'e'; - } - return src.length > srcPos + 3 && src[srcPos + 3] ? 'd' : 'c'; - } - if (src.length > srcPos + 2 && src[srcPos + 2]) { - return src.length > srcPos + 3 && src[srcPos + 3] ? 'b' : 'a'; - } - return src.length > srcPos + 3 && src[srcPos + 3] ? '9' : '8'; - } - if (src.length > srcPos + 1 && src[srcPos + 1]) { - if (src.length > srcPos + 2 && src[srcPos + 2]) { - return src.length > srcPos + 3 && src[srcPos + 3] ? '7' : '6'; - } - return src.length > srcPos + 3 && src[srcPos + 3] ? '5' : '4'; - } - if (src.length > srcPos + 2 && src[srcPos + 2]) { - return src.length > srcPos + 3 && src[srcPos + 3] ? '3' : '2'; - } - return src.length > srcPos + 3 && src[srcPos + 3] ? '1' : '0'; - } - - /** - *

- * Converts the 4 lsb of an int to a hexadecimal digit. - *

- *

- * 0 returns '0' - *

- *

- * 1 returns '1' - *

- *

- * 10 returns 'A' and so on... - *

- * - * @param nibble the 4 bits to convert - * @return a hexadecimal digit representing the 4 lsb of {@code nibble} - * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15} - */ - public static char intToHexDigit(final int nibble) { - final char c = Character.forDigit(nibble, 16); - if (c == Character.MIN_VALUE) { - throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble); - } - return c; - } - - /** - *

- * Converts the 4 lsb of an int to a hexadecimal digit encoded using the Msb0 - * bit ordering. - *

- *

- * 0 returns '0' - *

- *

- * 1 returns '8' - *

- *

- * 10 returns '5' and so on... - *

- * - * @param nibble the 4 bits to convert - * @return a hexadecimal digit representing the 4 lsb of {@code nibble} - * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15} - */ - public static char intToHexDigitMsb0(final int nibble) { - switch (nibble) { - case 0x0: - return '0'; - case 0x1: - return '8'; - case 0x2: - return '4'; - case 0x3: - return 'c'; - case 0x4: - return '2'; - case 0x5: - return 'a'; - case 0x6: - return '6'; - case 0x7: - return 'e'; - case 0x8: - return '1'; - case 0x9: - return '9'; - case 0xA: - return '5'; - case 0xB: - return 'd'; - case 0xC: - return '3'; - case 0xD: - return 'b'; - case 0xE: - return '7'; - case 0xF: - return 'f'; - default: - throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble); - } - } - - /** - *

- * Converts an array of int into a long using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the int array to convert - * @param srcPos the position in {@code src}, in int unit, from where to start - * the conversion - * @param dstInit initial value of the destination long - * @param dstPos the position of the lsb, in bits, in the result long - * @param nInts the number of ints to convert - * @return a long containing the selected bits - * @throws IllegalArgumentException if {@code (nInts-1)*32+dstPos >= 64} - * @throws NullPointerException if {@code src} is {@code null} - * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nInts > src.length} - */ - public static long intArrayToLong(final int[] src, final int srcPos, final long dstInit, final int dstPos, - final int nInts) { - if (src.length == 0 && srcPos == 0 || 0 == nInts) { - return dstInit; - } - if ((nInts - 1) * 32 + dstPos >= 64) { - throw new IllegalArgumentException("(nInts-1)*32+dstPos is greater or equal to than 64"); - } - long out = dstInit; - for (int i = 0; i < nInts; i++) { - final int shift = i * 32 + dstPos; - final long bits = (0xffffffffL & src[i + srcPos]) << shift; - final long mask = 0xffffffffL << shift; - out = (out & ~mask) | bits; - } - return out; - } - - /** - *

- * Converts an array of short into a long using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the short array to convert - * @param srcPos the position in {@code src}, in short unit, from where to - * start the conversion - * @param dstInit initial value of the destination long - * @param dstPos the position of the lsb, in bits, in the result long - * @param nShorts the number of shorts to convert - * @return a long containing the selected bits - * @throws NullPointerException if {@code src} is {@code null} - * @throws IllegalArgumentException if {@code (nShorts-1)*16+dstPos >= 64} - * @throws ArrayIndexOutOfBoundsException if - * {@code srcPos + nShorts > src.length} - */ - public static long shortArrayToLong(final short[] src, final int srcPos, final long dstInit, final int dstPos, - final int nShorts) { - if (src.length == 0 && srcPos == 0 || 0 == nShorts) { - return dstInit; - } - if ((nShorts - 1) * 16 + dstPos >= 64) { - throw new IllegalArgumentException("(nShorts-1)*16+dstPos is greater or equal to than 64"); - } - long out = dstInit; - for (int i = 0; i < nShorts; i++) { - final int shift = i * 16 + dstPos; - final long bits = (0xffffL & src[i + srcPos]) << shift; - final long mask = 0xffffL << shift; - out = (out & ~mask) | bits; - } - return out; - } - - /** - *

- * Converts an array of short into an int using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the short array to convert - * @param srcPos the position in {@code src}, in short unit, from where to - * start the conversion - * @param dstInit initial value of the destination int - * @param dstPos the position of the lsb, in bits, in the result int - * @param nShorts the number of shorts to convert - * @return an int containing the selected bits - * @throws NullPointerException if {@code src} is {@code null} - * @throws IllegalArgumentException if {@code (nShorts-1)*16+dstPos >= 32} - * @throws ArrayIndexOutOfBoundsException if - * {@code srcPos + nShorts > src.length} - */ - public static int shortArrayToInt(final short[] src, final int srcPos, final int dstInit, final int dstPos, - final int nShorts) { - if (src.length == 0 && srcPos == 0 || 0 == nShorts) { - return dstInit; - } - if ((nShorts - 1) * 16 + dstPos >= 32) { - throw new IllegalArgumentException("(nShorts-1)*16+dstPos is greater or equal to than 32"); - } - int out = dstInit; - for (int i = 0; i < nShorts; i++) { - final int shift = i * 16 + dstPos; - final int bits = (0xffff & src[i + srcPos]) << shift; - final int mask = 0xffff << shift; - out = (out & ~mask) | bits; - } - return out; - } - - /** - *

- * Converts an array of byte into a long using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the byte array to convert - * @param srcPos the position in {@code src}, in byte unit, from where to start - * the conversion - * @param dstInit initial value of the destination long - * @param dstPos the position of the lsb, in bits, in the result long - * @param nBytes the number of bytes to convert - * @return a long containing the selected bits - * @throws NullPointerException if {@code src} is {@code null} - * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 64} - * @throws ArrayIndexOutOfBoundsException if - * {@code srcPos + nBytes > src.length} - */ - public static long byteArrayToLong(final byte[] src, final int srcPos, final long dstInit, final int dstPos, - final int nBytes) { - if (src.length == 0 && srcPos == 0 || 0 == nBytes) { - return dstInit; - } - if ((nBytes - 1) * 8 + dstPos >= 64) { - throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 64"); - } - long out = dstInit; - for (int i = 0; i < nBytes; i++) { - final int shift = i * 8 + dstPos; - final long bits = (0xffL & src[i + srcPos]) << shift; - final long mask = 0xffL << shift; - out = (out & ~mask) | bits; - } - return out; - } - - /** - *

- * Converts an array of byte into an int using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the byte array to convert - * @param srcPos the position in {@code src}, in byte unit, from where to start - * the conversion - * @param dstInit initial value of the destination int - * @param dstPos the position of the lsb, in bits, in the result int - * @param nBytes the number of bytes to convert - * @return an int containing the selected bits - * @throws NullPointerException if {@code src} is {@code null} - * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 32} - * @throws ArrayIndexOutOfBoundsException if - * {@code srcPos + nBytes > src.length} - */ - public static int byteArrayToInt(final byte[] src, final int srcPos, final int dstInit, final int dstPos, - final int nBytes) { - if (src.length == 0 && srcPos == 0 || 0 == nBytes) { - return dstInit; - } - if ((nBytes - 1) * 8 + dstPos >= 32) { - throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 32"); - } - int out = dstInit; - for (int i = 0; i < nBytes; i++) { - final int shift = i * 8 + dstPos; - final int bits = (0xff & src[i + srcPos]) << shift; - final int mask = 0xff << shift; - out = (out & ~mask) | bits; - } - return out; - } - - /** - *

- * Converts an array of byte into a short using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the byte array to convert - * @param srcPos the position in {@code src}, in byte unit, from where to start - * the conversion - * @param dstInit initial value of the destination short - * @param dstPos the position of the lsb, in bits, in the result short - * @param nBytes the number of bytes to convert - * @return a short containing the selected bits - * @throws NullPointerException if {@code src} is {@code null} - * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 16} - * @throws ArrayIndexOutOfBoundsException if - * {@code srcPos + nBytes > src.length} - */ - public static short byteArrayToShort(final byte[] src, final int srcPos, final short dstInit, final int dstPos, - final int nBytes) { - if (src.length == 0 && srcPos == 0 || 0 == nBytes) { - return dstInit; - } - if ((nBytes - 1) * 8 + dstPos >= 16) { - throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 16"); - } - short out = dstInit; - for (int i = 0; i < nBytes; i++) { - final int shift = i * 8 + dstPos; - final int bits = (0xff & src[i + srcPos]) << shift; - final int mask = 0xff << shift; - out = (short) ((out & ~mask) | bits); - } - return out; - } - - /** - *

- * Converts an array of Char into a long using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the hex string to convert - * @param srcPos the position in {@code src}, in Char unit, from where to start - * the conversion - * @param dstInit initial value of the destination long - * @param dstPos the position of the lsb, in bits, in the result long - * @param nHex the number of Chars to convert - * @return a long containing the selected bits - * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 64} - */ - public static long hexToLong(final String src, final int srcPos, final long dstInit, final int dstPos, - final int nHex) { - if (0 == nHex) { - return dstInit; - } - if ((nHex - 1) * 4 + dstPos >= 64) { - throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 64"); - } - long out = dstInit; - for (int i = 0; i < nHex; i++) { - final int shift = i * 4 + dstPos; - final long bits = (0xfL & hexDigitToInt(src.charAt(i + srcPos))) << shift; - final long mask = 0xfL << shift; - out = (out & ~mask) | bits; - } - return out; - } - - /** - *

- * Converts an array of Char into an int using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the hex string to convert - * @param srcPos the position in {@code src}, in Char unit, from where to start - * the conversion - * @param dstInit initial value of the destination int - * @param dstPos the position of the lsb, in bits, in the result int - * @param nHex the number of Chars to convert - * @return an int containing the selected bits - * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 32} - */ - public static int hexToInt(final String src, final int srcPos, final int dstInit, final int dstPos, - final int nHex) { - if (0 == nHex) { - return dstInit; - } - if ((nHex - 1) * 4 + dstPos >= 32) { - throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 32"); - } - int out = dstInit; - for (int i = 0; i < nHex; i++) { - final int shift = i * 4 + dstPos; - final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift; - final int mask = 0xf << shift; - out = (out & ~mask) | bits; - } - return out; - } - - /** - *

- * Converts an array of Char into a short using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the hex string to convert - * @param srcPos the position in {@code src}, in Char unit, from where to start - * the conversion - * @param dstInit initial value of the destination short - * @param dstPos the position of the lsb, in bits, in the result short - * @param nHex the number of Chars to convert - * @return a short containing the selected bits - * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 16} - */ - public static short hexToShort(final String src, final int srcPos, final short dstInit, final int dstPos, - final int nHex) { - if (0 == nHex) { - return dstInit; - } - if ((nHex - 1) * 4 + dstPos >= 16) { - throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 16"); - } - short out = dstInit; - for (int i = 0; i < nHex; i++) { - final int shift = i * 4 + dstPos; - final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift; - final int mask = 0xf << shift; - out = (short) ((out & ~mask) | bits); - } - return out; - } - - /** - *

- * Converts an array of Char into a byte using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the hex string to convert - * @param srcPos the position in {@code src}, in Char unit, from where to start - * the conversion - * @param dstInit initial value of the destination byte - * @param dstPos the position of the lsb, in bits, in the result byte - * @param nHex the number of Chars to convert - * @return a byte containing the selected bits - * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 8} - */ - public static byte hexToByte(final String src, final int srcPos, final byte dstInit, final int dstPos, - final int nHex) { - if (0 == nHex) { - return dstInit; - } - if ((nHex - 1) * 4 + dstPos >= 8) { - throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 8"); - } - byte out = dstInit; - for (int i = 0; i < nHex; i++) { - final int shift = i * 4 + dstPos; - final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift; - final int mask = 0xf << shift; - out = (byte) ((out & ~mask) | bits); - } - return out; - } - - /** - *

- * Converts binary (represented as boolean array) into a long using the default - * (little endian, Lsb0) byte and bit ordering. - *

- * - * @param src the binary to convert - * @param srcPos the position in {@code src}, in boolean unit, from where to - * start the conversion - * @param dstInit initial value of the destination long - * @param dstPos the position of the lsb, in bits, in the result long - * @param nBools the number of booleans to convert - * @return a long containing the selected bits - * @throws NullPointerException if {@code src} is {@code null} - * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 64} - * @throws ArrayIndexOutOfBoundsException if - * {@code srcPos + nBools > src.length} - */ - public static long binaryToLong(final boolean[] src, final int srcPos, final long dstInit, final int dstPos, - final int nBools) { - if (src.length == 0 && srcPos == 0 || 0 == nBools) { - return dstInit; - } - if (nBools - 1 + dstPos >= 64) { - throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 64"); - } - long out = dstInit; - for (int i = 0; i < nBools; i++) { - final int shift = i + dstPos; - final long bits = (src[i + srcPos] ? 1L : 0) << shift; - final long mask = 0x1L << shift; - out = (out & ~mask) | bits; - } - return out; - } - - /** - *

- * Converts binary (represented as boolean array) into an int using the default - * (little endian, Lsb0) byte and bit ordering. - *

- * - * @param src the binary to convert - * @param srcPos the position in {@code src}, in boolean unit, from where to - * start the conversion - * @param dstInit initial value of the destination int - * @param dstPos the position of the lsb, in bits, in the result int - * @param nBools the number of booleans to convert - * @return an int containing the selected bits - * @throws NullPointerException if {@code src} is {@code null} - * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 32} - * @throws ArrayIndexOutOfBoundsException if - * {@code srcPos + nBools > src.length} - */ - public static int binaryToInt(final boolean[] src, final int srcPos, final int dstInit, final int dstPos, - final int nBools) { - if (src.length == 0 && srcPos == 0 || 0 == nBools) { - return dstInit; - } - if (nBools - 1 + dstPos >= 32) { - throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 32"); - } - int out = dstInit; - for (int i = 0; i < nBools; i++) { - final int shift = i + dstPos; - final int bits = (src[i + srcPos] ? 1 : 0) << shift; - final int mask = 0x1 << shift; - out = (out & ~mask) | bits; - } - return out; - } - - /** - *

- * Converts binary (represented as boolean array) into a short using the default - * (little endian, Lsb0) byte and bit ordering. - *

- * - * @param src the binary to convert - * @param srcPos the position in {@code src}, in boolean unit, from where to - * start the conversion - * @param dstInit initial value of the destination short - * @param dstPos the position of the lsb, in bits, in the result short - * @param nBools the number of booleans to convert - * @return a short containing the selected bits - * @throws NullPointerException if {@code src} is {@code null} - * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 16} - * @throws ArrayIndexOutOfBoundsException if - * {@code srcPos + nBools > src.length} - */ - public static short binaryToShort(final boolean[] src, final int srcPos, final short dstInit, final int dstPos, - final int nBools) { - if (src.length == 0 && srcPos == 0 || 0 == nBools) { - return dstInit; - } - if (nBools - 1 + dstPos >= 16) { - throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 16"); - } - short out = dstInit; - for (int i = 0; i < nBools; i++) { - final int shift = i + dstPos; - final int bits = (src[i + srcPos] ? 1 : 0) << shift; - final int mask = 0x1 << shift; - out = (short) ((out & ~mask) | bits); - } - return out; - } - - /** - *

- * Converts binary (represented as boolean array) into a byte using the default - * (little endian, Lsb0) byte and bit ordering. - *

- * - * @param src the binary to convert - * @param srcPos the position in {@code src}, in boolean unit, from where to - * start the conversion - * @param dstInit initial value of the destination byte - * @param dstPos the position of the lsb, in bits, in the result byte - * @param nBools the number of booleans to convert - * @return a byte containing the selected bits - * @throws NullPointerException if {@code src} is {@code null} - * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 8} - * @throws ArrayIndexOutOfBoundsException if - * {@code srcPos + nBools > src.length} - */ - public static byte binaryToByte(final boolean[] src, final int srcPos, final byte dstInit, final int dstPos, - final int nBools) { - if (src.length == 0 && srcPos == 0 || 0 == nBools) { - return dstInit; - } - if (nBools - 1 + dstPos >= 8) { - throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 8"); - } - byte out = dstInit; - for (int i = 0; i < nBools; i++) { - final int shift = i + dstPos; - final int bits = (src[i + srcPos] ? 1 : 0) << shift; - final int mask = 0x1 << shift; - out = (byte) ((out & ~mask) | bits); - } - return out; - } - - /** - *

- * Converts a long into an array of int using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the long to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nInts the number of ints to copy to {@code dst}, must be smaller or - * equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} and - * {@code nInts > 0} - * @throws IllegalArgumentException if {@code (nInts-1)*32+srcPos >= 64} - * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nInts > dst.length} - */ - public static int[] longToIntArray(final long src, final int srcPos, final int[] dst, final int dstPos, - final int nInts) { - if (0 == nInts) { - return dst; - } - if ((nInts - 1) * 32 + srcPos >= 64) { - throw new IllegalArgumentException("(nInts-1)*32+srcPos is greater or equal to than 64"); - } - for (int i = 0; i < nInts; i++) { - final int shift = i * 32 + srcPos; - dst[dstPos + i] = (int) (0xffffffff & (src >> shift)); - } - return dst; - } - - /** - *

- * Converts a long into an array of short using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the long to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nShorts the number of shorts to copy to {@code dst}, must be smaller - * or equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} - * @throws IllegalArgumentException if {@code (nShorts-1)*16+srcPos >= 64} - * @throws ArrayIndexOutOfBoundsException if - * {@code dstPos + nShorts > dst.length} - */ - public static short[] longToShortArray(final long src, final int srcPos, final short[] dst, final int dstPos, - final int nShorts) { - if (0 == nShorts) { - return dst; - } - if ((nShorts - 1) * 16 + srcPos >= 64) { - throw new IllegalArgumentException("(nShorts-1)*16+srcPos is greater or equal to than 64"); - } - for (int i = 0; i < nShorts; i++) { - final int shift = i * 16 + srcPos; - dst[dstPos + i] = (short) (0xffff & (src >> shift)); - } - return dst; - } - - /** - *

- * Converts an int into an array of short using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the int to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nShorts the number of shorts to copy to {@code dst}, must be smaller - * or equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} - * @throws IllegalArgumentException if {@code (nShorts-1)*16+srcPos >= 32} - * @throws ArrayIndexOutOfBoundsException if - * {@code dstPos + nShorts > dst.length} - */ - public static short[] intToShortArray(final int src, final int srcPos, final short[] dst, final int dstPos, - final int nShorts) { - if (0 == nShorts) { - return dst; - } - if ((nShorts - 1) * 16 + srcPos >= 32) { - throw new IllegalArgumentException("(nShorts-1)*16+srcPos is greater or equal to than 32"); - } - for (int i = 0; i < nShorts; i++) { - final int shift = i * 16 + srcPos; - dst[dstPos + i] = (short) (0xffff & (src >> shift)); - } - return dst; - } - - /** - *

- * Converts a long into an array of byte using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the long to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or - * equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} - * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 64} - * @throws ArrayIndexOutOfBoundsException if - * {@code dstPos + nBytes > dst.length} - */ - public static byte[] longToByteArray(final long src, final int srcPos, final byte[] dst, final int dstPos, - final int nBytes) { - if (0 == nBytes) { - return dst; - } - if ((nBytes - 1) * 8 + srcPos >= 64) { - throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 64"); - } - for (int i = 0; i < nBytes; i++) { - final int shift = i * 8 + srcPos; - dst[dstPos + i] = (byte) (0xff & (src >> shift)); - } - return dst; - } - - /** - *

- * Converts an int into an array of byte using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the int to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or - * equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} - * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 32} - * @throws ArrayIndexOutOfBoundsException if - * {@code dstPos + nBytes > dst.length} - */ - public static byte[] intToByteArray(final int src, final int srcPos, final byte[] dst, final int dstPos, - final int nBytes) { - if (0 == nBytes) { - return dst; - } - if ((nBytes - 1) * 8 + srcPos >= 32) { - throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 32"); - } - for (int i = 0; i < nBytes; i++) { - final int shift = i * 8 + srcPos; - dst[dstPos + i] = (byte) (0xff & (src >> shift)); - } - return dst; - } - - /** - *

- * Converts a short into an array of byte using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the short to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or - * equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} - * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 16} - * @throws ArrayIndexOutOfBoundsException if - * {@code dstPos + nBytes > dst.length} - */ - public static byte[] shortToByteArray(final short src, final int srcPos, final byte[] dst, final int dstPos, - final int nBytes) { - if (0 == nBytes) { - return dst; - } - if ((nBytes - 1) * 8 + srcPos >= 16) { - throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 16"); - } - for (int i = 0; i < nBytes; i++) { - final int shift = i * 8 + srcPos; - dst[dstPos + i] = (byte) (0xff & (src >> shift)); - } - return dst; - } - - /** - *

- * Converts a long into an array of Char using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the long to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dstInit the initial value for the result String - * @param dstPos the position in {@code dst} where to copy the result - * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or - * equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 64} - * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos} - */ - public static String longToHex(final long src, final int srcPos, final String dstInit, final int dstPos, - final int nHexs) { - if (0 == nHexs) { - return dstInit; - } - if ((nHexs - 1) * 4 + srcPos >= 64) { - throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 64"); - } - final StringBuilder sb = new StringBuilder(dstInit); - int append = sb.length(); - for (int i = 0; i < nHexs; i++) { - final int shift = i * 4 + srcPos; - final int bits = (int) (0xF & (src >> shift)); - if (dstPos + i == append) { - ++append; - sb.append(intToHexDigit(bits)); - } else { - sb.setCharAt(dstPos + i, intToHexDigit(bits)); - } - } - return sb.toString(); - } - - /** - *

- * Converts an int into an array of Char using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the int to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dstInit the initial value for the result String - * @param dstPos the position in {@code dst} where to copy the result - * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or - * equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 32} - * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos} - */ - public static String intToHex(final int src, final int srcPos, final String dstInit, final int dstPos, - final int nHexs) { - if (0 == nHexs) { - return dstInit; - } - if ((nHexs - 1) * 4 + srcPos >= 32) { - throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 32"); - } - final StringBuilder sb = new StringBuilder(dstInit); - int append = sb.length(); - for (int i = 0; i < nHexs; i++) { - final int shift = i * 4 + srcPos; - final int bits = 0xF & (src >> shift); - if (dstPos + i == append) { - ++append; - sb.append(intToHexDigit(bits)); - } else { - sb.setCharAt(dstPos + i, intToHexDigit(bits)); - } - } - return sb.toString(); - } - - /** - *

- * Converts a short into an array of Char using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the short to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dstInit the initial value for the result String - * @param dstPos the position in {@code dst} where to copy the result - * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or - * equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 16} - * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos} - */ - public static String shortToHex(final short src, final int srcPos, final String dstInit, final int dstPos, - final int nHexs) { - if (0 == nHexs) { - return dstInit; - } - if ((nHexs - 1) * 4 + srcPos >= 16) { - throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 16"); - } - final StringBuilder sb = new StringBuilder(dstInit); - int append = sb.length(); - for (int i = 0; i < nHexs; i++) { - final int shift = i * 4 + srcPos; - final int bits = 0xF & (src >> shift); - if (dstPos + i == append) { - ++append; - sb.append(intToHexDigit(bits)); - } else { - sb.setCharAt(dstPos + i, intToHexDigit(bits)); - } - } - return sb.toString(); - } - - /** - *

- * Converts a byte into an array of Char using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the byte to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dstInit the initial value for the result String - * @param dstPos the position in {@code dst} where to copy the result - * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or - * equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 8} - * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos} - */ - public static String byteToHex(final byte src, final int srcPos, final String dstInit, final int dstPos, - final int nHexs) { - if (0 == nHexs) { - return dstInit; - } - if ((nHexs - 1) * 4 + srcPos >= 8) { - throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 8"); - } - final StringBuilder sb = new StringBuilder(dstInit); - int append = sb.length(); - for (int i = 0; i < nHexs; i++) { - final int shift = i * 4 + srcPos; - final int bits = 0xF & (src >> shift); - if (dstPos + i == append) { - ++append; - sb.append(intToHexDigit(bits)); - } else { - sb.setCharAt(dstPos + i, intToHexDigit(bits)); - } - } - return sb.toString(); - } - - /** - *

- * Converts a long into an array of boolean using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the long to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nBools the number of booleans to copy to {@code dst}, must be smaller - * or equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} - * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 64} - * @throws ArrayIndexOutOfBoundsException if - * {@code dstPos + nBools > dst.length} - */ - public static boolean[] longToBinary(final long src, final int srcPos, final boolean[] dst, final int dstPos, - final int nBools) { - if (0 == nBools) { - return dst; - } - if (nBools - 1 + srcPos >= 64) { - throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 64"); - } - for (int i = 0; i < nBools; i++) { - final int shift = i + srcPos; - dst[dstPos + i] = (0x1 & (src >> shift)) != 0; - } - return dst; - } - - /** - *

- * Converts an int into an array of boolean using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the int to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nBools the number of booleans to copy to {@code dst}, must be smaller - * or equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} - * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 32} - * @throws ArrayIndexOutOfBoundsException if - * {@code dstPos + nBools > dst.length} - */ - public static boolean[] intToBinary(final int src, final int srcPos, final boolean[] dst, final int dstPos, - final int nBools) { - if (0 == nBools) { - return dst; - } - if (nBools - 1 + srcPos >= 32) { - throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 32"); - } - for (int i = 0; i < nBools; i++) { - final int shift = i + srcPos; - dst[dstPos + i] = (0x1 & (src >> shift)) != 0; - } - return dst; - } - - /** - *

- * Converts a short into an array of boolean using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the short to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nBools the number of booleans to copy to {@code dst}, must be smaller - * or equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} - * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 16} - * @throws ArrayIndexOutOfBoundsException if - * {@code dstPos + nBools > dst.length} - */ - public static boolean[] shortToBinary(final short src, final int srcPos, final boolean[] dst, final int dstPos, - final int nBools) { - if (0 == nBools) { - return dst; - } - if (nBools - 1 + srcPos >= 16) { - throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 16"); - } - assert (nBools - 1) < 16 - srcPos; - for (int i = 0; i < nBools; i++) { - final int shift = i + srcPos; - dst[dstPos + i] = (0x1 & (src >> shift)) != 0; - } - return dst; - } - - /** - *

- * Converts a byte into an array of boolean using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the byte to convert - * @param srcPos the position in {@code src}, in bits, from where to start the - * conversion - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nBools the number of booleans to copy to {@code dst}, must be smaller - * or equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} - * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 8} - * @throws ArrayIndexOutOfBoundsException if - * {@code dstPos + nBools > dst.length} - */ - public static boolean[] byteToBinary(final byte src, final int srcPos, final boolean[] dst, final int dstPos, - final int nBools) { - if (0 == nBools) { - return dst; - } - if (nBools - 1 + srcPos >= 8) { - throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 8"); - } - for (int i = 0; i < nBools; i++) { - final int shift = i + srcPos; - dst[dstPos + i] = (0x1 & (src >> shift)) != 0; - } - return dst; - } - - /** - *

- * Converts UUID into an array of byte using the default (little endian, Lsb0) - * byte and bit ordering. - *

- * - * @param src the UUID to convert - * @param dst the destination array - * @param dstPos the position in {@code dst} where to copy the result - * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or - * equal to the width of the input (from srcPos to msb) - * @return {@code dst} - * @throws NullPointerException if {@code dst} is {@code null} - * @throws IllegalArgumentException if {@code nBytes > 16} - * @throws ArrayIndexOutOfBoundsException if - * {@code dstPos + nBytes > dst.length} - */ - public static byte[] uuidToByteArray(final EaglercraftUUID src, final byte[] dst, final int dstPos, final int nBytes) { - if (0 == nBytes) { - return dst; - } - if (nBytes > 16) { - throw new IllegalArgumentException("nBytes is greater than 16"); - } - longToByteArray(src.getMostSignificantBits(), 0, dst, dstPos, Math.min(nBytes, 8)); - if (nBytes >= 8) { - longToByteArray(src.getLeastSignificantBits(), 0, dst, dstPos + 8, nBytes - 8); - } - return dst; - } - - /** - *

- * Converts bytes from an array into a UUID using the default (little endian, - * Lsb0) byte and bit ordering. - *

- * - * @param src the byte array to convert - * @param srcPos the position in {@code src} where to copy the result from - * @return a UUID - * @throws NullPointerException if {@code src} is {@code null} - * @throws IllegalArgumentException if array does not contain at least 16 bytes - * beginning with {@code srcPos} - */ - public static EaglercraftUUID byteArrayToUuid(final byte[] src, final int srcPos) { - if (src.length - srcPos < 16) { - throw new IllegalArgumentException("Need at least 16 bytes for UUID"); - } - return new EaglercraftUUID(byteArrayToLong(src, srcPos, 0, 0, 8), byteArrayToLong(src, srcPos + 8, 0, 0, 8)); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/EnumUtils.java b/sources/main/java/org/apache/commons/lang3/EnumUtils.java deleted file mode 100644 index add3eabf..00000000 --- a/sources/main/java/org/apache/commons/lang3/EnumUtils.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** - *

- * Utility library to provide helper methods for Java enums. - *

- * - *

- * #ThreadSafe# - *

- * - * @since 3.0 - */ -public class EnumUtils { - - private static final String NULL_ELEMENTS_NOT_PERMITTED = "null elements not permitted"; - private static final String CANNOT_STORE_S_S_VALUES_IN_S_BITS = "Cannot store %s %s values in %s bits"; - private static final String S_DOES_NOT_SEEM_TO_BE_AN_ENUM_TYPE = "%s does not seem to be an Enum type"; - private static final String ENUM_CLASS_MUST_BE_DEFINED = "EnumClass must be defined."; - - /** - * Validate {@code enumClass}. - * - * @param the type of the enumeration - * @param enumClass to check - * @return {@code enumClass} - * @throws NullPointerException if {@code enumClass} is {@code null} - * @throws IllegalArgumentException if {@code enumClass} is not an enum class - * @since 3.2 - */ - private static > Class asEnum(final Class enumClass) { - Validate.notNull(enumClass, ENUM_CLASS_MUST_BE_DEFINED); - Validate.isTrue(enumClass.isEnum(), S_DOES_NOT_SEEM_TO_BE_AN_ENUM_TYPE, enumClass); - return enumClass; - } - - /** - * Validate that {@code enumClass} is compatible with representation in a - * {@code long}. - * - * @param the type of the enumeration - * @param enumClass to check - * @return {@code enumClass} - * @throws NullPointerException if {@code enumClass} is {@code null} - * @throws IllegalArgumentException if {@code enumClass} is not an enum class or - * has more than 64 values - * @since 3.0.1 - */ - private static > Class checkBitVectorable(final Class enumClass) { - final E[] constants = asEnum(enumClass).getEnumConstants(); - Validate.isTrue(constants.length <= Long.SIZE, CANNOT_STORE_S_S_VALUES_IN_S_BITS, - Integer.valueOf(constants.length), enumClass.getSimpleName(), Integer.valueOf(Long.SIZE)); - - return enumClass; - } - - /** - *

- * Creates a long bit vector representation of the given array of Enum values. - *

- * - *

- * This generates a value that is usable by {@link EnumUtils#processBitVector}. - *

- * - *

- * Do not use this method if you have more than 64 values in your Enum, as this - * would create a value greater than a long can hold. - *

- * - * @param enumClass the class of the enum we are working with, not {@code null} - * @param values the values we want to convert, not {@code null} - * @param the type of the enumeration - * @return a long whose value provides a binary representation of the given set - * of enum values. - * @throws NullPointerException if {@code enumClass} or {@code values} is - * {@code null} - * @throws IllegalArgumentException if {@code enumClass} is not an enum class or - * has more than 64 values - * @since 3.0.1 - * @see #generateBitVectors(Class, Iterable) - */ - @SafeVarargs - public static > long generateBitVector(final Class enumClass, final E... values) { - Validate.noNullElements(values); - return generateBitVector(enumClass, Arrays.asList(values)); - } - - /** - *

- * Creates a long bit vector representation of the given subset of an Enum. - *

- * - *

- * This generates a value that is usable by {@link EnumUtils#processBitVector}. - *

- * - *

- * Do not use this method if you have more than 64 values in your Enum, as this - * would create a value greater than a long can hold. - *

- * - * @param enumClass the class of the enum we are working with, not {@code null} - * @param values the values we want to convert, not {@code null}, neither - * containing {@code null} - * @param the type of the enumeration - * @return a long whose value provides a binary representation of the given set - * of enum values. - * @throws NullPointerException if {@code enumClass} or {@code values} is - * {@code null} - * @throws IllegalArgumentException if {@code enumClass} is not an enum class or - * has more than 64 values, or if any - * {@code values} {@code null} - * @since 3.0.1 - * @see #generateBitVectors(Class, Iterable) - */ - public static > long generateBitVector(final Class enumClass, - final Iterable values) { - checkBitVectorable(enumClass); - Validate.notNull(values); - long total = 0; - for (final E constant : values) { - Validate.notNull(constant, NULL_ELEMENTS_NOT_PERMITTED); - total |= 1L << constant.ordinal(); - } - return total; - } - - /** - *

- * Gets the enum for the class, returning {@code null} if not found. - *

- * - *

- * This method differs from {@link Enum#valueOf} in that it does not throw an - * exception for an invalid enum name. - *

- * - * @param the type of the enumeration - * @param enumClass the class of the enum to query, not null - * @param enumName the enum name, null returns null - * @return the enum, null if not found - */ - public static > E getEnum(final Class enumClass, final String enumName) { - return getEnum(enumClass, enumName, null); - } - - /** - *

- * Gets the enum for the class, returning {@code defaultEnum} if not found. - *

- * - *

- * This method differs from {@link Enum#valueOf} in that it does not throw an - * exception for an invalid enum name. - *

- * - * @param the type of the enumeration - * @param enumClass the class of the enum to query, not null - * @param enumName the enum name, null returns default enum - * @param defaultEnum the default enum - * @return the enum, default enum if not found - * @since 3.10 - */ - public static > E getEnum(final Class enumClass, final String enumName, final E defaultEnum) { - if (enumName == null) { - return defaultEnum; - } - try { - return Enum.valueOf(enumClass, enumName); - } catch (final IllegalArgumentException ex) { - return defaultEnum; - } - } - - /** - *

- * Gets the enum for the class, returning {@code null} if not found. - *

- * - *

- * This method differs from {@link Enum#valueOf} in that it does not throw an - * exception for an invalid enum name and performs case insensitive matching of - * the name. - *

- * - * @param the type of the enumeration - * @param enumClass the class of the enum to query, not null - * @param enumName the enum name, null returns null - * @return the enum, null if not found - * @since 3.8 - */ - public static > E getEnumIgnoreCase(final Class enumClass, final String enumName) { - return getEnumIgnoreCase(enumClass, enumName, null); - } - - /** - *

- * Gets the enum for the class, returning {@code defaultEnum} if not found. - *

- * - *

- * This method differs from {@link Enum#valueOf} in that it does not throw an - * exception for an invalid enum name and performs case insensitive matching of - * the name. - *

- * - * @param the type of the enumeration - * @param enumClass the class of the enum to query, not null - * @param enumName the enum name, null returns default enum - * @param defaultEnum the default enum - * @return the enum, default enum if not found - * @since 3.10 - */ - public static > E getEnumIgnoreCase(final Class enumClass, final String enumName, - final E defaultEnum) { - if (enumName == null || !enumClass.isEnum()) { - return defaultEnum; - } - for (final E each : enumClass.getEnumConstants()) { - if (each.name().equalsIgnoreCase(enumName)) { - return each; - } - } - return defaultEnum; - } - - /** - *

- * Gets the {@code List} of enums. - *

- * - *

- * This method is useful when you need a list of enums rather than an array. - *

- * - * @param the type of the enumeration - * @param enumClass the class of the enum to query, not null - * @return the modifiable list of enums, never null - */ - public static > List getEnumList(final Class enumClass) { - return new ArrayList<>(Arrays.asList(enumClass.getEnumConstants())); - } - - /** - *

- * Gets the {@code Map} of enums by name. - *

- * - *

- * This method is useful when you need a map of enums by name. - *

- * - * @param the type of the enumeration - * @param enumClass the class of the enum to query, not null - * @return the modifiable map of enum names to enums, never null - */ - public static > Map getEnumMap(final Class enumClass) { - final Map map = new LinkedHashMap<>(); - for (final E e : enumClass.getEnumConstants()) { - map.put(e.name(), e); - } - return map; - } - - /** - *

- * Checks if the specified name is a valid enum for the class. - *

- * - *

- * This method differs from {@link Enum#valueOf} in that checks if the name is a - * valid enum without needing to catch the exception. - *

- * - * @param the type of the enumeration - * @param enumClass the class of the enum to query, not null - * @param enumName the enum name, null returns false - * @return true if the enum name is valid, otherwise false - */ - public static > boolean isValidEnum(final Class enumClass, final String enumName) { - return getEnum(enumClass, enumName) != null; - } - - /** - *

- * Checks if the specified name is a valid enum for the class. - *

- * - *

- * This method differs from {@link Enum#valueOf} in that checks if the name is a - * valid enum without needing to catch the exception and performs case - * insensitive matching of the name. - *

- * - * @param the type of the enumeration - * @param enumClass the class of the enum to query, not null - * @param enumName the enum name, null returns false - * @return true if the enum name is valid, otherwise false - * @since 3.8 - */ - public static > boolean isValidEnumIgnoreCase(final Class enumClass, final String enumName) { - return getEnumIgnoreCase(enumClass, enumName) != null; - } - - /** - * This constructor is public to permit tools that require a JavaBean instance - * to operate. - */ - public EnumUtils() { - } -} diff --git a/sources/main/java/org/apache/commons/lang3/Functions.java b/sources/main/java/org/apache/commons/lang3/Functions.java deleted file mode 100644 index 97a70e82..00000000 --- a/sources/main/java/org/apache/commons/lang3/Functions.java +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.lang.reflect.UndeclaredThrowableException; -import java.util.Collection; -import java.util.Objects; -import java.util.concurrent.Callable; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Stream; - -import org.apache.commons.lang3.Streams.FailableStream; -import org.apache.commons.lang3.function.FailableBooleanSupplier; - -/** - * This class provides utility functions, and classes for working with the - * {@code java.util.function} package, or more generally, with Java 8 lambdas. - * More specifically, it attempts to address the fact that lambdas are supposed - * not to throw Exceptions, at least not checked Exceptions, AKA instances of - * {@link Exception}. This enforces the use of constructs like: - * - *
- * {
- * 	@code
- * 	Consumer consumer = m -> {
- * 		try {
- * 			m.invoke(o, args);
- * 		} catch (Throwable t) {
- * 			throw Functions.rethrow(t);
- * 		}
- * 	};
- * }
- * 
- * - *

- * By replacing a {@link java.util.function.Consumer Consumer<O>} with a - * {@link FailableConsumer FailableConsumer<O,? extends Throwable>}, this - * can be written like follows: - *

- * - *
- * {@code
- *   Functions.accept((m) -> m.invoke(o,args));
- * }
- * 
- * - *

- * Obviously, the second version is much more concise and the spirit of Lambda - * expressions is met better than the second version. - *

- * - * @since 3.9 - * @deprecated Use {@link org.apache.commons.lang3.function.Failable}. - */ -@Deprecated -public class Functions { - - /** - * A functional interface like {@link BiConsumer} that declares a - * {@code Throwable}. - * - *

- * TODO for 4.0: Move to org.apache.commons.lang3.function. - *

- * - * @param Consumed type 1. - * @param Consumed type 2. - * @param Thrown exception. - * @deprecated Use {@link org.apache.commons.lang3.function.FailableBiConsumer}. - */ - @Deprecated - @FunctionalInterface - public interface FailableBiConsumer { - - /** - * Accepts the consumer. - * - * @param object1 the first parameter for the consumable to accept - * @param object2 the second parameter for the consumable to accept - * @throws T Thrown when the consumer fails. - */ - void accept(O1 object1, O2 object2) throws T; - } - - /** - * A functional interface like {@link BiFunction} that declares a - * {@code Throwable}. - * - *

- * TODO for 4.0: Move to org.apache.commons.lang3.function. - *

- * - * @param Input type 1. - * @param Input type 2. - * @param Return type. - * @param Thrown exception. - * @deprecated Use {@link org.apache.commons.lang3.function.FailableBiFunction}. - */ - @Deprecated - @FunctionalInterface - public interface FailableBiFunction { - - /** - * Applies this function. - * - * @param input1 the first input for the function - * @param input2 the second input for the function - * @return the result of the function - * @throws T Thrown when the function fails. - */ - R apply(O1 input1, O2 input2) throws T; - } - - /** - * A functional interface like {@link BiPredicate} that declares a - * {@code Throwable}. - * - *

- * TODO for 4.0: Move to org.apache.commons.lang3.function. - *

- * - * @param Predicate type 1. - * @param Predicate type 2. - * @param Thrown exception. - * @deprecated Use - * {@link org.apache.commons.lang3.function.FailableBiPredicate}. - */ - @Deprecated - @FunctionalInterface - public interface FailableBiPredicate { - - /** - * Tests the predicate. - * - * @param object1 the first object to test the predicate on - * @param object2 the second object to test the predicate on - * @return the predicate's evaluation - * @throws T if the predicate fails - */ - boolean test(O1 object1, O2 object2) throws T; - } - - /** - * A functional interface like {@link java.util.concurrent.Callable} that - * declares a {@code Throwable}. - * - *

- * TODO for 4.0: Move to org.apache.commons.lang3.function. - *

- * - * @param Return type. - * @param Thrown exception. - * @deprecated Use {@link org.apache.commons.lang3.function.FailableCallable}. - */ - @Deprecated - @FunctionalInterface - public interface FailableCallable { - - /** - * Calls the callable. - * - * @return The value returned from the callable - * @throws T if the callable fails - */ - R call() throws T; - } - - /** - * A functional interface like {@link Consumer} that declares a - * {@code Throwable}. - * - *

- * TODO for 4.0: Move to org.apache.commons.lang3.function. - *

- * - * @param Consumed type 1. - * @param Thrown exception. - * @deprecated Use {@link org.apache.commons.lang3.function.FailableConsumer}. - */ - @Deprecated - @FunctionalInterface - public interface FailableConsumer { - - /** - * Accepts the consumer. - * - * @param object the parameter for the consumable to accept - * @throws T Thrown when the consumer fails. - */ - void accept(O object) throws T; - } - - /** - * A functional interface like {@link Function} that declares a - * {@code Throwable}. - * - *

- * TODO for 4.0: Move to org.apache.commons.lang3.function. - *

- * - * @param Input type 1. - * @param Return type. - * @param Thrown exception. - * @deprecated Use {@link org.apache.commons.lang3.function.FailableFunction}. - */ - @Deprecated - @FunctionalInterface - public interface FailableFunction { - - /** - * Applies this function. - * - * @param input the input for the function - * @return the result of the function - * @throws T Thrown when the function fails. - */ - R apply(I input) throws T; - } - - /** - * A functional interface like {@link Predicate} that declares a - * {@code Throwable}. - * - *

- * TODO for 4.0: Move to org.apache.commons.lang3.function. - *

- * - * @param Predicate type 1. - * @param Thrown exception. - * @deprecated Use {@link org.apache.commons.lang3.function.FailablePredicate}. - */ - @Deprecated - @FunctionalInterface - public interface FailablePredicate { - - /** - * Tests the predicate. - * - * @param object the object to test the predicate on - * @return the predicate's evaluation - * @throws T if the predicate fails - */ - boolean test(I object) throws T; - } - - /** - * A functional interface like {@link Runnable} that declares a - * {@code Throwable}. - * - *

- * TODO for 4.0: Move to org.apache.commons.lang3.function. - *

- * - * @param Thrown exception. - * @deprecated Use {@link org.apache.commons.lang3.function.FailableRunnable}. - */ - @Deprecated - @FunctionalInterface - public interface FailableRunnable { - - /** - * Runs the function. - * - * @throws T Thrown when the function fails. - */ - void run() throws T; - } - - /** - * A functional interface like {@link Supplier} that declares a - * {@code Throwable}. - * - *

- * TODO for 4.0: Move to org.apache.commons.lang3.function. - *

- * - * @param Return type. - * @param Thrown exception. - * @deprecated Use {@link org.apache.commons.lang3.function.FailableSupplier}. - */ - @Deprecated - @FunctionalInterface - public interface FailableSupplier { - - /** - * Supplies an object - * - * @return a result - * @throws T if the supplier fails - */ - R get() throws T; - } - - /** - * Consumes a consumer and rethrows any exception as a {@link RuntimeException}. - * - * @param consumer the consumer to consume - * @param object1 the first object to consume by {@code consumer} - * @param object2 the second object to consume by {@code consumer} - * @param the type of the first argument the consumer accepts - * @param the type of the second argument the consumer accepts - * @param the type of checked exception the consumer may throw - */ - public static void accept(final FailableBiConsumer consumer, - final O1 object1, final O2 object2) { - run(() -> consumer.accept(object1, object2)); - } - - /** - * Consumes a consumer and rethrows any exception as a {@link RuntimeException}. - * - * @param consumer the consumer to consume - * @param object the object to consume by {@code consumer} - * @param the type the consumer accepts - * @param the type of checked exception the consumer may throw - */ - public static void accept(final FailableConsumer consumer, final O object) { - run(() -> consumer.accept(object)); - } - - /** - * Applies a function and rethrows any exception as a {@link RuntimeException}. - * - * @param function the function to apply - * @param input1 the first input to apply {@code function} on - * @param input2 the second input to apply {@code function} on - * @param the type of the first argument the function accepts - * @param the type of the second argument the function accepts - * @param the return type of the function - * @param the type of checked exception the function may throw - * @return the value returned from the function - */ - public static O apply(final FailableBiFunction function, - final O1 input1, final O2 input2) { - return get(() -> function.apply(input1, input2)); - } - - /** - * Applies a function and rethrows any exception as a {@link RuntimeException}. - * - * @param function the function to apply - * @param input the input to apply {@code function} on - * @param the type of the argument the function accepts - * @param the return type of the function - * @param the type of checked exception the function may throw - * @return the value returned from the function - */ - public static O apply(final FailableFunction function, final I input) { - return get(() -> function.apply(input)); - } - - /** - * Converts the given {@link FailableBiConsumer} into a standard - * {@link BiConsumer}. - * - * @param the type of the first argument of the consumers - * @param the type of the second argument of the consumers - * @param consumer a failable {@code BiConsumer} - * @return a standard {@code BiConsumer} - * @since 3.10 - */ - public static BiConsumer asBiConsumer(final FailableBiConsumer consumer) { - return (input1, input2) -> accept(consumer, input1, input2); - } - - /** - * Converts the given {@link FailableBiFunction} into a standard - * {@link BiFunction}. - * - * @param the type of the first argument of the input of the functions - * @param the type of the second argument of the input of the functions - * @param the type of the output of the functions - * @param function a {@code FailableBiFunction} - * @return a standard {@code BiFunction} - * @since 3.10 - */ - public static BiFunction asBiFunction(final FailableBiFunction function) { - return (input1, input2) -> apply(function, input1, input2); - } - - /** - * Converts the given {@link FailableBiPredicate} into a standard - * {@link BiPredicate}. - * - * @param the type of the first argument used by the predicates - * @param the type of the second argument used by the predicates - * @param predicate a {@code FailableBiPredicate} - * @return a standard {@code BiPredicate} - * @since 3.10 - */ - public static BiPredicate asBiPredicate(final FailableBiPredicate predicate) { - return (input1, input2) -> test(predicate, input1, input2); - } - - /** - * Converts the given {@link FailableCallable} into a standard {@link Callable}. - * - * @param the type used by the callables - * @param callable a {@code FailableCallable} - * @return a standard {@code Callable} - * @since 3.10 - */ - public static Callable asCallable(final FailableCallable callable) { - return () -> call(callable); - } - - /** - * Converts the given {@link FailableConsumer} into a standard {@link Consumer}. - * - * @param the type used by the consumers - * @param consumer a {@code FailableConsumer} - * @return a standard {@code Consumer} - * @since 3.10 - */ - public static Consumer asConsumer(final FailableConsumer consumer) { - return input -> accept(consumer, input); - } - - /** - * Converts the given {@link FailableFunction} into a standard {@link Function}. - * - * @param the type of the input of the functions - * @param the type of the output of the functions - * @param function a {code FailableFunction} - * @return a standard {@code Function} - * @since 3.10 - */ - public static Function asFunction(final FailableFunction function) { - return input -> apply(function, input); - } - - /** - * Converts the given {@link FailablePredicate} into a standard - * {@link Predicate}. - * - * @param the type used by the predicates - * @param predicate a {@code FailablePredicate} - * @return a standard {@code Predicate} - * @since 3.10 - */ - public static Predicate asPredicate(final FailablePredicate predicate) { - return input -> test(predicate, input); - } - - /** - * Converts the given {@link FailableRunnable} into a standard {@link Runnable}. - * - * @param runnable a {@code FailableRunnable} - * @return a standard {@code Runnable} - * @since 3.10 - */ - public static Runnable asRunnable(final FailableRunnable runnable) { - return () -> run(runnable); - } - - /** - * Converts the given {@link FailableSupplier} into a standard {@link Supplier}. - * - * @param the type supplied by the suppliers - * @param supplier a {@code FailableSupplier} - * @return a standard {@code Supplier} - * @since 3.10 - */ - public static Supplier asSupplier(final FailableSupplier supplier) { - return () -> get(supplier); - } - - /** - * Calls a callable and rethrows any exception as a {@link RuntimeException}. - * - * @param callable the callable to call - * @param the return type of the callable - * @param the type of checked exception the callable may throw - * @return the value returned from the callable - */ - public static O call(final FailableCallable callable) { - return get(callable::call); - } - - /** - * Invokes a supplier, and returns the result. - * - * @param supplier The supplier to invoke. - * @param The suppliers output type. - * @param The type of checked exception, which the supplier can throw. - * @return The object, which has been created by the supplier - * @since 3.10 - */ - public static O get(final FailableSupplier supplier) { - try { - return supplier.get(); - } catch (final Throwable t) { - throw rethrow(t); - } - } - - /** - * Invokes a boolean supplier, and returns the result. - * - * @param supplier The boolean supplier to invoke. - * @param The type of checked exception, which the supplier can throw. - * @return The boolean, which has been created by the supplier - */ - private static boolean getAsBoolean(final FailableBooleanSupplier supplier) { - try { - return supplier.getAsBoolean(); - } catch (final Throwable t) { - throw rethrow(t); - } - } - - /** - *

- * Rethrows a {@link Throwable} as an unchecked exception. If the argument is - * already unchecked, namely a {@code RuntimeException} or {@code Error} then - * the argument will be rethrown without modification. If the exception is - * {@code IOException} then it will be wrapped into a - * {@code UncheckedIOException}. In every other cases the exception will be - * wrapped into a {@code - * UndeclaredThrowableException} - *

- * - *

- * Note that there is a declared return type for this method, even though it - * never returns. The reason for that is to support the usual pattern: - *

- * - *
-	 * throw rethrow(myUncheckedException);
-	 * 
- * - *

- * instead of just calling the method. This pattern may help the Java compiler - * to recognize that at that point an exception will be thrown and the code flow - * analysis will not demand otherwise mandatory commands that could follow the - * method call, like a {@code return} statement from a value returning method. - *

- * - * @param throwable The throwable to rethrow ossibly wrapped into an unchecked - * exception - * @return Never returns anything, this method never terminates normally. - */ - public static RuntimeException rethrow(final Throwable throwable) { - Objects.requireNonNull(throwable, "throwable"); - if (throwable instanceof RuntimeException) { - throw (RuntimeException) throwable; - } else if (throwable instanceof Error) { - throw (Error) throwable; - } else if (throwable instanceof IOException) { - throw new UncheckedIOException((IOException) throwable); - } else { - throw new UndeclaredThrowableException(throwable); - } - } - - /** - * Runs a runnable and rethrows any exception as a {@link RuntimeException}. - * - * @param runnable The runnable to run - * @param the type of checked exception the runnable may throw - */ - public static void run(final FailableRunnable runnable) { - try { - runnable.run(); - } catch (final Throwable t) { - throw rethrow(t); - } - } - - /** - * Converts the given collection into a {@link FailableStream}. The - * {@link FailableStream} consists of the collections elements. Shortcut for - * - *
-	 * Functions.stream(collection.stream());
-	 * 
- * - * @param collection The collection, which is being converted into a - * {@link FailableStream}. - * @param The collections element type. (In turn, the result streams - * element type.) - * @return The created {@link FailableStream}. - * @since 3.10 - */ - public static FailableStream stream(final Collection collection) { - return new FailableStream<>(collection.stream()); - } - - /** - * Converts the given stream into a {@link FailableStream}. The - * {@link FailableStream} consists of the same elements, than the input stream. - * However, failable lambdas, like {@link FailablePredicate}, - * {@link FailableFunction}, and {@link FailableConsumer} may be applied, rather - * than {@link Predicate}, {@link Function}, {@link Consumer}, etc. - * - * @param stream The stream, which is being converted into a - * {@link FailableStream}. - * @param The streams element type. - * @return The created {@link FailableStream}. - * @since 3.10 - */ - public static FailableStream stream(final Stream stream) { - return new FailableStream<>(stream); - } - - /** - * Tests a predicate and rethrows any exception as a {@link RuntimeException}. - * - * @param predicate the predicate to test - * @param object1 the first input to test by {@code predicate} - * @param object2 the second input to test by {@code predicate} - * @param the type of the first argument the predicate tests - * @param the type of the second argument the predicate tests - * @param the type of checked exception the predicate may throw - * @return the boolean value returned by the predicate - */ - public static boolean test(final FailableBiPredicate predicate, - final O1 object1, final O2 object2) { - return getAsBoolean(() -> predicate.test(object1, object2)); - } - - /** - * Tests a predicate and rethrows any exception as a {@link RuntimeException}. - * - * @param predicate the predicate to test - * @param object the input to test by {@code predicate} - * @param the type of argument the predicate tests - * @param the type of checked exception the predicate may throw - * @return the boolean value returned by the predicate - */ - public static boolean test(final FailablePredicate predicate, final O object) { - return getAsBoolean(() -> predicate.test(object)); - } - - /** - * A simple try-with-resources implementation, that can be used, if your objects - * do not implement the {@link AutoCloseable} interface. The method executes the - * {@code action}. The method guarantees, that all the - * {@code resources} are being executed, in the given order, afterwards, and - * regardless of success, or failure. If either the original action, or any of - * the resource action fails, then the first failure (AKA - * {@link Throwable} is rethrown. Example use: - * - *
-	 * {
-	 * 	@code
-	 * 	final FileInputStream fis = new FileInputStream("my.file");
-	 * 	Functions.tryWithResources(useInputStream(fis), null, () -> fis.close());
-	 * }
-	 * 
- * - * @param action The action to execute. This object will always - * be invoked. - * @param errorHandler An optional error handler, which will be invoked finally, - * if any error occurred. The error handler will receive the - * first error, AKA {@link Throwable}. - * @param resources The resource actions to execute. All resource - * actions will be invoked, in the given order. A resource - * action is an instance of {@link FailableRunnable}, which - * will be executed. - * @see #tryWithResources(FailableRunnable, FailableRunnable...) - */ - @SafeVarargs - public static void tryWithResources(final FailableRunnable action, - final FailableConsumer errorHandler, - final FailableRunnable... resources) { - final FailableConsumer actualErrorHandler; - if (errorHandler == null) { - actualErrorHandler = Functions::rethrow; - } else { - actualErrorHandler = errorHandler; - } - if (resources != null) { - for (final FailableRunnable failableRunnable : resources) { - Objects.requireNonNull(failableRunnable, "runnable"); - } - } - Throwable th = null; - try { - action.run(); - } catch (final Throwable t) { - th = t; - } - if (resources != null) { - for (final FailableRunnable runnable : resources) { - try { - runnable.run(); - } catch (final Throwable t) { - if (th == null) { - th = t; - } - } - } - } - if (th != null) { - try { - actualErrorHandler.accept(th); - } catch (final Throwable t) { - throw rethrow(t); - } - } - } - - /** - * A simple try-with-resources implementation, that can be used, if your objects - * do not implement the {@link AutoCloseable} interface. The method executes the - * {@code action}. The method guarantees, that all the - * {@code resources} are being executed, in the given order, afterwards, and - * regardless of success, or failure. If either the original action, or any of - * the resource action fails, then the first failure (AKA - * {@link Throwable} is rethrown. Example use: - * - *
-	 * {
-	 * 	@code
-	 * 	final FileInputStream fis = new FileInputStream("my.file");
-	 * 	Functions.tryWithResources(useInputStream(fis), () -> fis.close());
-	 * }
-	 * 
- * - * @param action The action to execute. This object will always be - * invoked. - * @param resources The resource actions to execute. All resource - * actions will be invoked, in the given order. A resource - * action is an instance of {@link FailableRunnable}, which - * will be executed. - * @see #tryWithResources(FailableRunnable, FailableConsumer, - * FailableRunnable...) - */ - @SafeVarargs - public static void tryWithResources(final FailableRunnable action, - final FailableRunnable... resources) { - tryWithResources(action, null, resources); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/JavaVersion.java b/sources/main/java/org/apache/commons/lang3/JavaVersion.java deleted file mode 100644 index 39a16100..00000000 --- a/sources/main/java/org/apache/commons/lang3/JavaVersion.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import org.apache.commons.lang3.math.NumberUtils; - -/** - *

- * An enum representing all the versions of the Java specification. This is - * intended to mirror available values from the - * java.specification.version System property. - *

- * - * @since 3.0 - */ -public enum JavaVersion { - - /** - * The Java version reported by Android. This is not an official Java version - * number. - */ - JAVA_0_9(1.5f, "0.9"), - - /** - * Java 1.1. - */ - JAVA_1_1(1.1f, "1.1"), - - /** - * Java 1.2. - */ - JAVA_1_2(1.2f, "1.2"), - - /** - * Java 1.3. - */ - JAVA_1_3(1.3f, "1.3"), - - /** - * Java 1.4. - */ - JAVA_1_4(1.4f, "1.4"), - - /** - * Java 1.5. - */ - JAVA_1_5(1.5f, "1.5"), - - /** - * Java 1.6. - */ - JAVA_1_6(1.6f, "1.6"), - - /** - * Java 1.7. - */ - JAVA_1_7(1.7f, "1.7"), - - /** - * Java 1.8. - */ - JAVA_1_8(1.8f, "1.8"), - - /** - * Java 1.9. - * - * @deprecated As of release 3.5, replaced by {@link #JAVA_9} - */ - @Deprecated - JAVA_1_9(9.0f, "9"), - - /** - * Java 9. - * - * @since 3.5 - */ - JAVA_9(9.0f, "9"), - - /** - * Java 10. - * - * @since 3.7 - */ - JAVA_10(10.0f, "10"), - - /** - * Java 11. - * - * @since 3.8 - */ - JAVA_11(11.0f, "11"), - - /** - * Java 12. - * - * @since 3.9 - */ - JAVA_12(12.0f, "12"), - - /** - * Java 13. - * - * @since 3.9 - */ - JAVA_13(13.0f, "13"), - - /** - * Java 14. - * - * @since 3.11 - */ - JAVA_14(14.0f, "14"), - - /** - * Java 15. - * - * @since 3.11 - */ - JAVA_15(15.0f, "15"), - - /** - * Java 16. - * - * @since 3.11 - */ - JAVA_16(16.0f, "16"), - - /** - * Java 17. - * - * @since 3.12.0 - */ - JAVA_17(17.0f, "17"), - - /** - * The most recent java version. Mainly introduced to avoid to break when a new - * version of Java is used. - */ - JAVA_RECENT(maxVersion(), Float.toString(maxVersion())); - - /** - * The float value. - */ - private final float value; - - /** - * The standard name. - */ - private final String name; - - /** - * Constructor. - * - * @param value the float value - * @param name the standard name, not null - */ - JavaVersion(final float value, final String name) { - this.value = value; - this.name = name; - } - - // ----------------------------------------------------------------------- - /** - *

- * Whether this version of Java is at least the version of Java passed in. - *

- * - *

- * For example:
- * {@code myVersion.atLeast(JavaVersion.JAVA_1_4)} - *

- * - * @param requiredVersion the version to check against, not null - * @return true if this version is equal to or greater than the specified - * version - */ - public boolean atLeast(final JavaVersion requiredVersion) { - return this.value >= requiredVersion.value; - } - - // ----------------------------------------------------------------------- - /** - *

- * Whether this version of Java is at most the version of Java passed in. - *

- * - *

- * For example:
- * {@code myVersion.atMost(JavaVersion.JAVA_1_4)} - *

- * - * @param requiredVersion the version to check against, not null - * @return true if this version is equal to or greater than the specified - * version - * @since 3.9 - */ - public boolean atMost(final JavaVersion requiredVersion) { - return this.value <= requiredVersion.value; - } - - /** - * Transforms the given string with a Java version number to the corresponding - * constant of this enumeration class. This method is used internally. - * - * @param nom the Java version as string - * @return the corresponding enumeration constant or null if the version - * is unknown - */ - // helper for static importing - static JavaVersion getJavaVersion(final String nom) { - return get(nom); - } - - /** - * Transforms the given string with a Java version number to the corresponding - * constant of this enumeration class. This method is used internally. - * - * @param versionStr the Java version as string - * @return the corresponding enumeration constant or null if the version - * is unknown - */ - static JavaVersion get(final String versionStr) { - if (versionStr == null) { - return null; - } - switch (versionStr) { - case "0.9": - return JAVA_0_9; - case "1.1": - return JAVA_1_1; - case "1.2": - return JAVA_1_2; - case "1.3": - return JAVA_1_3; - case "1.4": - return JAVA_1_4; - case "1.5": - return JAVA_1_5; - case "1.6": - return JAVA_1_6; - case "1.7": - return JAVA_1_7; - case "1.8": - return JAVA_1_8; - case "9": - return JAVA_9; - case "10": - return JAVA_10; - case "11": - return JAVA_11; - case "12": - return JAVA_12; - case "13": - return JAVA_13; - case "14": - return JAVA_14; - case "15": - return JAVA_15; - case "16": - return JAVA_16; - case "17": - return JAVA_17; - default: - final float v = toFloatVersion(versionStr); - if ((v - 1.) < 1.) { // then we need to check decimals > .9 - final int firstComma = Math.max(versionStr.indexOf('.'), versionStr.indexOf(',')); - final int end = Math.max(versionStr.length(), versionStr.indexOf(',', firstComma)); - if (Float.parseFloat(versionStr.substring(firstComma + 1, end)) > .9f) { - return JAVA_RECENT; - } - } else if (v > 10) { - return JAVA_RECENT; - } - return null; - } - } - - // ----------------------------------------------------------------------- - /** - *

- * The string value is overridden to return the standard name. - *

- * - *

- * For example, {@code "1.5"}. - *

- * - * @return the name, not null - */ - @Override - public String toString() { - return name; - } - - /** - * Gets the Java Version from the system or 99.0 if the - * {@code java.specification.version} system property is not set. - * - * @return the value of {@code java.specification.version} system property or - * 99.0 if it is not set. - */ - private static float maxVersion() { - final float v = toFloatVersion(System.getProperty("java.specification.version", "99.0")); - if (v > 0) { - return v; - } - return 99f; - } - - /** - * Parses a float value from a String. - * - * @param value the String to parse. - * @return the float value represented by the string or -1 if the given String - * can not be parsed. - */ - private static float toFloatVersion(final String value) { - final int defaultReturnValue = -1; - if (value.contains(".")) { - final String[] toParse = value.split("\\."); - if (toParse.length >= 2) { - return NumberUtils.toFloat(toParse[0] + '.' + toParse[1], defaultReturnValue); - } - } else { - return NumberUtils.toFloat(value, defaultReturnValue); - } - return defaultReturnValue; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/LocaleUtils.java b/sources/main/java/org/apache/commons/lang3/LocaleUtils.java deleted file mode 100644 index b26e7403..00000000 --- a/sources/main/java/org/apache/commons/lang3/LocaleUtils.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -/** - *

- * Operations to assist when working with a {@link Locale}. - *

- * - *

- * This class tries to handle {@code null} input gracefully. An exception will - * not be thrown for a {@code null} input. Each method documents its behavior in - * more detail. - *

- * - * @since 2.2 - */ -public class LocaleUtils { - - // class to avoid synchronization (Init on demand) - static class SyncAvoid { - /** Unmodifiable list of available locales. */ - private static final List AVAILABLE_LOCALE_LIST; - /** Unmodifiable set of available locales. */ - private static final Set AVAILABLE_LOCALE_SET; - - static { - final List list = new ArrayList<>(Arrays.asList(Locale.getAvailableLocales())); // extra safe - AVAILABLE_LOCALE_LIST = Collections.unmodifiableList(list); - AVAILABLE_LOCALE_SET = Collections.unmodifiableSet(new HashSet<>(list)); - } - } - - /** Concurrent map of language locales by country. */ - private static final Map> cLanguagesByCountry = new HashMap<>(); - - /** Concurrent map of country locales by language. */ - private static final Map> cCountriesByLanguage = new HashMap<>(); - - /** - *

- * Obtains an unmodifiable list of installed locales. - *

- * - *

- * This method is a wrapper around {@link Locale#getAvailableLocales()}. It is - * more efficient, as the JDK method must create a new array each time it is - * called. - *

- * - * @return the unmodifiable list of available locales - */ - public static List availableLocaleList() { - return SyncAvoid.AVAILABLE_LOCALE_LIST; - } - - /** - *

- * Obtains an unmodifiable set of installed locales. - *

- * - *

- * This method is a wrapper around {@link Locale#getAvailableLocales()}. It is - * more efficient, as the JDK method must create a new array each time it is - * called. - *

- * - * @return the unmodifiable set of available locales - */ - public static Set availableLocaleSet() { - return SyncAvoid.AVAILABLE_LOCALE_SET; - } - - /** - *

- * Obtains the list of countries supported for a given language. - *

- * - *

- * This method takes a language code and searches to find the countries - * available for that language. Variant locales are removed. - *

- * - * @param languageCode the 2 letter language code, null returns empty - * @return an unmodifiable List of Locale objects, not null - */ - public static List countriesByLanguage(final String languageCode) { - if (languageCode == null) { - return Collections.emptyList(); - } - List countries = cCountriesByLanguage.get(languageCode); - if (countries == null) { - countries = new ArrayList<>(); - final List locales = availableLocaleList(); - for (final Locale locale : locales) { - if (languageCode.equals(locale.getLanguage()) && !locale.getCountry().isEmpty() - && locale.getVariant().isEmpty()) { - countries.add(locale); - } - } - countries = Collections.unmodifiableList(countries); - cCountriesByLanguage.putIfAbsent(languageCode, countries); - countries = cCountriesByLanguage.get(languageCode); - } - return countries; - } - - /** - *

- * Checks if the locale specified is in the list of available locales. - *

- * - * @param locale the Locale object to check if it is available - * @return true if the locale is a known locale - */ - public static boolean isAvailableLocale(final Locale locale) { - return availableLocaleList().contains(locale); - } - - /** - * Checks whether the given String is a ISO 3166 alpha-2 country code. - * - * @param str the String to check - * @return true, is the given String is a ISO 3166 compliant country code. - */ - private static boolean isISO3166CountryCode(final String str) { - return StringUtils.isAllUpperCase(str) && str.length() == 2; - } - - /** - * Checks whether the given String is a ISO 639 compliant language code. - * - * @param str the String to check. - * @return true, if the given String is a ISO 639 compliant language code. - */ - private static boolean isISO639LanguageCode(final String str) { - return StringUtils.isAllLowerCase(str) && (str.length() == 2 || str.length() == 3); - } - - /** - * Checks whether the given String is a UN M.49 numeric area code. - * - * @param str the String to check - * @return true, is the given String is a UN M.49 numeric area code. - */ - private static boolean isNumericAreaCode(final String str) { - return StringUtils.isNumeric(str) && str.length() == 3; - } - - /** - *

- * Obtains the list of languages supported for a given country. - *

- * - *

- * This method takes a country code and searches to find the languages available - * for that country. Variant locales are removed. - *

- * - * @param countryCode the 2 letter country code, null returns empty - * @return an unmodifiable List of Locale objects, not null - */ - public static List languagesByCountry(final String countryCode) { - if (countryCode == null) { - return Collections.emptyList(); - } - List langs = cLanguagesByCountry.get(countryCode); - if (langs == null) { - langs = new ArrayList<>(); - final List locales = availableLocaleList(); - for (final Locale locale : locales) { - if (countryCode.equals(locale.getCountry()) && locale.getVariant().isEmpty()) { - langs.add(locale); - } - } - langs = Collections.unmodifiableList(langs); - cLanguagesByCountry.putIfAbsent(countryCode, langs); - langs = cLanguagesByCountry.get(countryCode); - } - return langs; - } - - /** - *

- * Obtains the list of locales to search through when performing a locale - * search. - *

- * - *
-	 * localeLookupList(Locale("fr", "CA", "xxx"))
-	 *   = [Locale("fr", "CA", "xxx"), Locale("fr", "CA"), Locale("fr")]
-	 * 
- * - * @param locale the locale to start from - * @return the unmodifiable list of Locale objects, 0 being locale, not null - */ - public static List localeLookupList(final Locale locale) { - return localeLookupList(locale, locale); - } - - /** - *

- * Obtains the list of locales to search through when performing a locale - * search. - *

- * - *
-	 * localeLookupList(Locale("fr", "CA", "xxx"), Locale("en"))
-	 *   = [Locale("fr", "CA", "xxx"), Locale("fr", "CA"), Locale("fr"), Locale("en"]
-	 * 
- * - *

- * The result list begins with the most specific locale, then the next more - * general and so on, finishing with the default locale. The list will never - * contain the same locale twice. - *

- * - * @param locale the locale to start from, null returns empty list - * @param defaultLocale the default locale to use if no other is found - * @return the unmodifiable list of Locale objects, 0 being locale, not null - */ - public static List localeLookupList(final Locale locale, final Locale defaultLocale) { - final List list = new ArrayList<>(4); - if (locale != null) { - list.add(locale); - if (!locale.getVariant().isEmpty()) { - list.add(new Locale(locale.getLanguage(), locale.getCountry())); - } - if (!locale.getCountry().isEmpty()) { - list.add(new Locale(locale.getLanguage(), StringUtils.EMPTY)); - } - if (!list.contains(defaultLocale)) { - list.add(defaultLocale); - } - } - return Collections.unmodifiableList(list); - } - - /** - * Tries to parse a locale from the given String. - * - * @param str the String to parse a locale from. - * @return a Locale instance parsed from the given String. - * @throws IllegalArgumentException if the given String can not be parsed. - */ - private static Locale parseLocale(final String str) { - if (isISO639LanguageCode(str)) { - return new Locale(str); - } - - final String[] segments = str.split("_", -1); - final String language = segments[0]; - if (segments.length == 2) { - final String country = segments[1]; - if (isISO639LanguageCode(language) && isISO3166CountryCode(country) || isNumericAreaCode(country)) { - return new Locale(language, country); - } - } else if (segments.length == 3) { - final String country = segments[1]; - final String variant = segments[2]; - if (isISO639LanguageCode(language) - && (country.isEmpty() || isISO3166CountryCode(country) || isNumericAreaCode(country)) - && !variant.isEmpty()) { - return new Locale(language, country, variant); - } - } - throw new IllegalArgumentException("Invalid locale format: " + str); - } - - /** - * Returns the given locale if non-{@code null}, otherwise - * {@link Locale#getDefault()}. - * - * @param locale a locale or {@code null}. - * @return the given locale if non-{@code null}, otherwise - * {@link Locale#getDefault()}. - * @since 3.12.0 - */ - public static Locale toLocale(final Locale locale) { - return locale != null ? locale : Locale.getDefault(); - } - - /** - *

- * Converts a String to a Locale. - *

- * - *

- * This method takes the string format of a locale and creates the locale object - * from it. - *

- * - *
-	 *   LocaleUtils.toLocale("")           = new Locale("", "")
-	 *   LocaleUtils.toLocale("en")         = new Locale("en", "")
-	 *   LocaleUtils.toLocale("en_GB")      = new Locale("en", "GB")
-	 *   LocaleUtils.toLocale("en_001")     = new Locale("en", "001")
-	 *   LocaleUtils.toLocale("en_GB_xxx")  = new Locale("en", "GB", "xxx")   (#)
-	 * 
- * - *

- * (#) The behavior of the JDK variant constructor changed between JDK1.3 and - * JDK1.4. In JDK1.3, the constructor upper cases the variant, in JDK1.4, it - * doesn't. Thus, the result from getVariant() may vary depending on your JDK. - *

- * - *

- * This method validates the input strictly. The language code must be - * lowercase. The country code must be uppercase. The separator must be an - * underscore. The length must be correct. - *

- * - * @param str the locale String to convert, null returns null - * @return a Locale, null if null input - * @throws IllegalArgumentException if the string is an invalid format - * @see Locale#forLanguageTag(String) - */ - public static Locale toLocale(final String str) { - if (str == null) { - return null; - } - if (str.isEmpty()) { // LANG-941 - JDK 8 introduced an empty locale where all fields are blank - return new Locale(StringUtils.EMPTY, StringUtils.EMPTY); - } - if (str.contains("#")) { // LANG-879 - Cannot handle Java 7 script & extensions - throw new IllegalArgumentException("Invalid locale format: " + str); - } - final int len = str.length(); - if (len < 2) { - throw new IllegalArgumentException("Invalid locale format: " + str); - } - final char ch0 = str.charAt(0); - if (ch0 == '_') { - if (len < 3) { - throw new IllegalArgumentException("Invalid locale format: " + str); - } - final char ch1 = str.charAt(1); - final char ch2 = str.charAt(2); - if (!Character.isUpperCase(ch1) || !Character.isUpperCase(ch2)) { - throw new IllegalArgumentException("Invalid locale format: " + str); - } - if (len == 3) { - return new Locale(StringUtils.EMPTY, str.substring(1, 3)); - } - if (len < 5) { - throw new IllegalArgumentException("Invalid locale format: " + str); - } - if (str.charAt(3) != '_') { - throw new IllegalArgumentException("Invalid locale format: " + str); - } - return new Locale(StringUtils.EMPTY, str.substring(1, 3), str.substring(4)); - } - - return parseLocale(str); - } - - /** - *

- * {@code LocaleUtils} instances should NOT be constructed in standard - * programming. Instead, the class should be used as - * {@code LocaleUtils.toLocale("en_GB");}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public LocaleUtils() { - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/NotImplementedException.java b/sources/main/java/org/apache/commons/lang3/NotImplementedException.java deleted file mode 100644 index 58c82f6d..00000000 --- a/sources/main/java/org/apache/commons/lang3/NotImplementedException.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -/** - *

- * Thrown to indicate that a block of code has not been implemented. This - * exception supplements {@code UnsupportedOperationException} by providing a - * more semantically rich description of the problem. - *

- * - *

- * {@code NotImplementedException} represents the case where the author has yet - * to implement the logic at this point in the program. This can act as an - * exception based TODO tag. - *

- * - *
- * public void foo() {
- * 	try {
- * 		// do something that throws an Exception
- * 	} catch (Exception ex) {
- * 		// don't know what to do here yet
- * 		throw new NotImplementedException("TODO", ex);
- * 	}
- * }
- * 
- * - * This class was originally added in Lang 2.0, but removed in 3.0. - * - * @since 3.2 - */ -public class NotImplementedException extends UnsupportedOperationException { - - private static final long serialVersionUID = 20131021L; - - private final String code; - - /** - * Constructs a NotImplementedException. - * - * @since 3.10 - */ - public NotImplementedException() { - this.code = null; - } - - /** - * Constructs a NotImplementedException. - * - * @param message description of the exception - * @since 3.2 - */ - public NotImplementedException(final String message) { - this(message, (String) null); - } - - /** - * Constructs a NotImplementedException. - * - * @param cause cause of the exception - * @since 3.2 - */ - public NotImplementedException(final Throwable cause) { - this(cause, null); - } - - /** - * Constructs a NotImplementedException. - * - * @param message description of the exception - * @param cause cause of the exception - * @since 3.2 - */ - public NotImplementedException(final String message, final Throwable cause) { - this(message, cause, null); - } - - /** - * Constructs a NotImplementedException. - * - * @param message description of the exception - * @param code code indicating a resource for more information regarding the - * lack of implementation - * @since 3.2 - */ - public NotImplementedException(final String message, final String code) { - super(message); - this.code = code; - } - - /** - * Constructs a NotImplementedException. - * - * @param cause cause of the exception - * @param code code indicating a resource for more information regarding the - * lack of implementation - * @since 3.2 - */ - public NotImplementedException(final Throwable cause, final String code) { - super(cause); - this.code = code; - } - - /** - * Constructs a NotImplementedException. - * - * @param message description of the exception - * @param cause cause of the exception - * @param code code indicating a resource for more information regarding the - * lack of implementation - * @since 3.2 - */ - public NotImplementedException(final String message, final Throwable cause, final String code) { - super(message, cause); - this.code = code; - } - - /** - * Obtain the not implemented code. This is an unformatted piece of text - * intended to point to further information regarding the lack of - * implementation. It might, for example, be an issue tracker ID or a URL. - * - * @return a code indicating a resource for more information regarding the lack - * of implementation - */ - public String getCode() { - return this.code; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/ObjectUtils.java b/sources/main/java/org/apache/commons/lang3/ObjectUtils.java deleted file mode 100644 index 6f10917c..00000000 --- a/sources/main/java/org/apache/commons/lang3/ObjectUtils.java +++ /dev/null @@ -1,1377 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.io.IOException; -import java.io.Serializable; -import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.time.Duration; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Map; -import java.util.Objects; -import java.util.TreeSet; -import java.util.function.Supplier; - -import org.apache.commons.lang3.exception.CloneFailedException; -import org.apache.commons.lang3.text.StrBuilder; -import org.apache.commons.lang3.time.DurationUtils; - -/** - *

- * Operations on {@code Object}. - *

- * - *

- * This class tries to handle {@code null} input gracefully. An exception will - * generally not be thrown for a {@code null} input. Each method documents its - * behavior in more detail. - *

- * - *

- * #ThreadSafe# - *

- * - * @since 1.0 - */ -//@Immutable -@SuppressWarnings("deprecation") // deprecated class StrBuilder is imported -// because it is part of the signature of deprecated methods -public class ObjectUtils { - - // Null - // ----------------------------------------------------------------------- - /** - *

- * Class used as a null placeholder where {@code null} has another meaning. - *

- * - *

- * For example, in a {@code HashMap} the - * {@link java.util.HashMap#get(java.lang.Object)} method returns {@code null} - * if the {@code Map} contains {@code null} or if there is no matching key. The - * {@code Null} placeholder can be used to distinguish between these two cases. - *

- * - *

- * Another example is {@code Hashtable}, where {@code null} cannot be stored. - *

- */ - public static class Null implements Serializable { - /** - * Required for serialization support. Declare serialization compatibility with - * Commons Lang 1.0 - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 7092611880189329093L; - - /** - * Restricted constructor - singleton. - */ - Null() { - } - - /** - *

- * Ensure singleton. - *

- * - * @return the singleton value - */ - private Object readResolve() { - return NULL; - } - } - - private static final char AT_SIGN = '@'; - - /** - *

- * Singleton used as a {@code null} placeholder where {@code null} has another - * meaning. - *

- * - *

- * For example, in a {@code HashMap} the - * {@link java.util.HashMap#get(java.lang.Object)} method returns {@code null} - * if the {@code Map} contains {@code null} or if there is no matching key. The - * {@code Null} placeholder can be used to distinguish between these two cases. - *

- * - *

- * Another example is {@code Hashtable}, where {@code null} cannot be stored. - *

- * - *

- * This instance is Serializable. - *

- */ - public static final Null NULL = new Null(); - - /** - * Checks if all values in the array are not {@code nulls}. - * - *

- * If any value is {@code null} or the array is {@code null} then {@code false} - * is returned. If all elements in array are not {@code null} or the array is - * empty (contains no elements) {@code true} is returned. - *

- * - *
-	 * ObjectUtils.allNotNull(*)             = true
-	 * ObjectUtils.allNotNull(*, *)          = true
-	 * ObjectUtils.allNotNull(null)          = false
-	 * ObjectUtils.allNotNull(null, null)    = false
-	 * ObjectUtils.allNotNull(null, *)       = false
-	 * ObjectUtils.allNotNull(*, null)       = false
-	 * ObjectUtils.allNotNull(*, *, null, *) = false
-	 * 
- * - * @param values the values to test, may be {@code null} or empty - * @return {@code false} if there is at least one {@code null} value in the - * array or the array is {@code null}, {@code true} if all values in the - * array are not {@code null}s or array contains no elements. - * @since 3.5 - */ - public static boolean allNotNull(final Object... values) { - if (values == null) { - return false; - } - - for (final Object val : values) { - if (val == null) { - return false; - } - } - - return true; - } - - /** - * Checks if all values in the given array are {@code null}. - * - *

- * If all the values are {@code null} or the array is {@code null} or empty, - * then {@code true} is returned, otherwise {@code false} is returned. - *

- * - *
-	 * ObjectUtils.allNull(*)                = false
-	 * ObjectUtils.allNull(*, null)          = false
-	 * ObjectUtils.allNull(null, *)          = false
-	 * ObjectUtils.allNull(null, null, *, *) = false
-	 * ObjectUtils.allNull(null)             = true
-	 * ObjectUtils.allNull(null, null)       = true
-	 * 
- * - * @param values the values to test, may be {@code null} or empty - * @return {@code true} if all values in the array are {@code null}s, - * {@code false} if there is at least one non-null value in the array. - * @since 3.11 - */ - public static boolean allNull(final Object... values) { - return !anyNotNull(values); - } - - /** - * Checks if any value in the given array is not {@code null}. - * - *

- * If all the values are {@code null} or the array is {@code null} or empty then - * {@code false} is returned. Otherwise {@code true} is returned. - *

- * - *
-	 * ObjectUtils.anyNotNull(*)                = true
-	 * ObjectUtils.anyNotNull(*, null)          = true
-	 * ObjectUtils.anyNotNull(null, *)          = true
-	 * ObjectUtils.anyNotNull(null, null, *, *) = true
-	 * ObjectUtils.anyNotNull(null)             = false
-	 * ObjectUtils.anyNotNull(null, null)       = false
-	 * 
- * - * @param values the values to test, may be {@code null} or empty - * @return {@code true} if there is at least one non-null value in the array, - * {@code false} if all values in the array are {@code null}s. If the - * array is {@code null} or empty {@code false} is also returned. - * @since 3.5 - */ - public static boolean anyNotNull(final Object... values) { - return firstNonNull(values) != null; - } - - /** - * Checks if any value in the given array is {@code null}. - * - *

- * If any of the values are {@code null} or the array is {@code null}, then - * {@code true} is returned, otherwise {@code false} is returned. - *

- * - *
-	 * ObjectUtils.anyNull(*)             = false
-	 * ObjectUtils.anyNull(*, *)          = false
-	 * ObjectUtils.anyNull(null)          = true
-	 * ObjectUtils.anyNull(null, null)    = true
-	 * ObjectUtils.anyNull(null, *)       = true
-	 * ObjectUtils.anyNull(*, null)       = true
-	 * ObjectUtils.anyNull(*, *, null, *) = true
-	 * 
- * - * @param values the values to test, may be {@code null} or empty - * @return {@code true} if there is at least one {@code null} value in the - * array, {@code false} if all the values are non-null. If the array is - * {@code null} or empty, {@code true} is also returned. - * @since 3.11 - */ - public static boolean anyNull(final Object... values) { - return !allNotNull(values); - } - - // cloning - // ----------------------------------------------------------------------- - /** - *

- * Clone an object. - *

- * - * @param the type of the object - * @param obj the object to clone, null returns null - * @return the clone if the object implements {@link Cloneable} otherwise - * {@code null} - * @throws CloneFailedException if the object is cloneable and the clone - * operation fails - * @since 3.0 - */ - public static T clone(final T obj) { - if (obj instanceof Cloneable) { - final Object result; - if (obj.getClass().isArray()) { - final Class componentType = obj.getClass().getComponentType(); - if (componentType.isPrimitive()) { - int length = Array.getLength(obj); - result = Array.newInstance(componentType, length); - while (length-- > 0) { - Array.set(result, length, Array.get(obj, length)); - } - } else { - result = ((Object[]) obj).clone(); - } - } else { - try { - final Method clone = obj.getClass().getMethod("clone"); - result = clone.invoke(obj); - } catch (final NoSuchMethodException e) { - throw new CloneFailedException( - "Cloneable type " + obj.getClass().getName() + " has no clone method", e); - } catch (final IllegalAccessException e) { - throw new CloneFailedException("Cannot clone Cloneable type " + obj.getClass().getName(), e); - } catch (final InvocationTargetException e) { - throw new CloneFailedException("Exception cloning Cloneable type " + obj.getClass().getName(), - e.getCause()); - } - } - @SuppressWarnings("unchecked") // OK because input is of type T - final T checked = (T) result; - return checked; - } - - return null; - } - - /** - *

- * Clone an object if possible. - *

- * - *

- * This method is similar to {@link #clone(Object)}, but will return the - * provided instance as the return value instead of {@code null} if the instance - * is not cloneable. This is more convenient if the caller uses different - * implementations (e.g. of a service) and some of the implementations do not - * allow concurrent processing or have state. In such cases the implementation - * can simply provide a proper clone implementation and the caller's code does - * not have to change. - *

- * - * @param the type of the object - * @param obj the object to clone, null returns null - * @return the clone if the object implements {@link Cloneable} otherwise the - * object itself - * @throws CloneFailedException if the object is cloneable and the clone - * operation fails - * @since 3.0 - */ - public static T cloneIfPossible(final T obj) { - final T clone = clone(obj); - return clone == null ? obj : clone; - } - - /** - *

- * Null safe comparison of Comparables. {@code null} is assumed to be less than - * a non-{@code null} value. - *

- * - * @param type of the values processed by this method - * @param c1 the first comparable, may be null - * @param c2 the second comparable, may be null - * @return a negative value if c1 < c2, zero if c1 = c2 and a positive value - * if c1 > c2 - */ - public static > int compare(final T c1, final T c2) { - return compare(c1, c2, false); - } - - /** - *

- * Null safe comparison of Comparables. - *

- * - * @param type of the values processed by this method - * @param c1 the first comparable, may be null - * @param c2 the second comparable, may be null - * @param nullGreater if true {@code null} is considered greater than a - * non-{@code null} value or if false {@code null} is - * considered less than a Non-{@code null} value - * @return a negative value if c1 < c2, zero if c1 = c2 and a positive value - * if c1 > c2 - * @see java.util.Comparator#compare(Object, Object) - */ - public static > int compare(final T c1, final T c2, final boolean nullGreater) { - if (c1 == c2) { - return 0; - } else if (c1 == null) { - return nullGreater ? 1 : -1; - } else if (c2 == null) { - return nullGreater ? -1 : 1; - } - return c1.compareTo(c2); - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static boolean MAGIC_FLAG = ObjectUtils.CONST(true);
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param v the boolean value to return - * @return the boolean v, unchanged - * @since 3.2 - */ - public static boolean CONST(final boolean v) { - return v; - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static byte MAGIC_BYTE = ObjectUtils.CONST((byte) 127);
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param v the byte value to return - * @return the byte v, unchanged - * @since 3.2 - */ - public static byte CONST(final byte v) { - return v; - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static char MAGIC_CHAR = ObjectUtils.CONST('a');
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param v the char value to return - * @return the char v, unchanged - * @since 3.2 - */ - public static char CONST(final char v) { - return v; - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static double MAGIC_DOUBLE = ObjectUtils.CONST(1.0);
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param v the double value to return - * @return the double v, unchanged - * @since 3.2 - */ - public static double CONST(final double v) { - return v; - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static float MAGIC_FLOAT = ObjectUtils.CONST(1.0f);
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param v the float value to return - * @return the float v, unchanged - * @since 3.2 - */ - public static float CONST(final float v) { - return v; - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static int MAGIC_INT = ObjectUtils.CONST(123);
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param v the int value to return - * @return the int v, unchanged - * @since 3.2 - */ - public static int CONST(final int v) { - return v; - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static long MAGIC_LONG = ObjectUtils.CONST(123L);
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param v the long value to return - * @return the long v, unchanged - * @since 3.2 - */ - public static long CONST(final long v) { - return v; - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static short MAGIC_SHORT = ObjectUtils.CONST((short) 123);
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param v the short value to return - * @return the short v, unchanged - * @since 3.2 - */ - public static short CONST(final short v) { - return v; - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static String MAGIC_STRING = ObjectUtils.CONST("abc");
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param the Object type - * @param v the genericized Object value to return (typically a String). - * @return the genericized Object v, unchanged (typically a String). - * @since 3.2 - */ - public static T CONST(final T v) { - return v; - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static byte MAGIC_BYTE = ObjectUtils.CONST_BYTE(127);
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param v the byte literal (as an int) value to return - * @throws IllegalArgumentException if the value passed to v is larger than a - * byte, that is, smaller than -128 or larger - * than 127. - * @return the byte v, unchanged - * @since 3.2 - */ - public static byte CONST_BYTE(final int v) { - if (v < Byte.MIN_VALUE || v > Byte.MAX_VALUE) { - throw new IllegalArgumentException( - "Supplied value must be a valid byte literal between -128 and 127: [" + v + "]"); - } - return (byte) v; - } - - /** - * This method returns the provided value unchanged. This can prevent javac from - * inlining a constant field, e.g., - * - *
-	 * public final static short MAGIC_SHORT = ObjectUtils.CONST_SHORT(127);
-	 * 
- * - * This way any jars that refer to this field do not have to recompile - * themselves if the field's value changes at some future date. - * - * @param v the short literal (as an int) value to return - * @throws IllegalArgumentException if the value passed to v is larger than a - * short, that is, smaller than -32768 or - * larger than 32767. - * @return the byte v, unchanged - * @since 3.2 - */ - public static short CONST_SHORT(final int v) { - if (v < Short.MIN_VALUE || v > Short.MAX_VALUE) { - throw new IllegalArgumentException( - "Supplied value must be a valid byte literal between -32768 and 32767: [" + v + "]"); - } - return (short) v; - } - - /** - *

- * Returns a default value if the object passed is {@code null}. - *

- * - *
-	 * ObjectUtils.defaultIfNull(null, null)      = null
-	 * ObjectUtils.defaultIfNull(null, "")        = ""
-	 * ObjectUtils.defaultIfNull(null, "zz")      = "zz"
-	 * ObjectUtils.defaultIfNull("abc", *)        = "abc"
-	 * ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
-	 * 
- * - * @param the type of the object - * @param object the {@code Object} to test, may be {@code null} - * @param defaultValue the default value to return, may be {@code null} - * @return {@code object} if it is not {@code null}, defaultValue otherwise TODO - * Rename to getIfNull in 4.0 - */ - public static T defaultIfNull(final T object, final T defaultValue) { - return object != null ? object : defaultValue; - } - - // Null-safe equals/hashCode - // ----------------------------------------------------------------------- - /** - *

- * Compares two objects for equality, where either one or both objects may be - * {@code null}. - *

- * - *
-	 * ObjectUtils.equals(null, null)                  = true
-	 * ObjectUtils.equals(null, "")                    = false
-	 * ObjectUtils.equals("", null)                    = false
-	 * ObjectUtils.equals("", "")                      = true
-	 * ObjectUtils.equals(Boolean.TRUE, null)          = false
-	 * ObjectUtils.equals(Boolean.TRUE, "true")        = false
-	 * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE)  = true
-	 * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
-	 * 
- * - * @param object1 the first object, may be {@code null} - * @param object2 the second object, may be {@code null} - * @return {@code true} if the values of both objects are the same - * @deprecated this method has been replaced by - * {@code java.util.Objects.equals(Object, Object)} in Java 7 and - * will be removed from future releases. - */ - @Deprecated - public static boolean equals(final Object object1, final Object object2) { - if (object1 == object2) { - return true; - } - if (object1 == null || object2 == null) { - return false; - } - return object1.equals(object2); - } - - /** - *

- * Returns the first value in the array which is not {@code null}. If all the - * values are {@code null} or the array is {@code null} or empty then - * {@code null} is returned. - *

- * - *
-	 * ObjectUtils.firstNonNull(null, null)      = null
-	 * ObjectUtils.firstNonNull(null, "")        = ""
-	 * ObjectUtils.firstNonNull(null, null, "")  = ""
-	 * ObjectUtils.firstNonNull(null, "zz")      = "zz"
-	 * ObjectUtils.firstNonNull("abc", *)        = "abc"
-	 * ObjectUtils.firstNonNull(null, "xyz", *)  = "xyz"
-	 * ObjectUtils.firstNonNull(Boolean.TRUE, *) = Boolean.TRUE
-	 * ObjectUtils.firstNonNull()                = null
-	 * 
- * - * @param the component type of the array - * @param values the values to test, may be {@code null} or empty - * @return the first value from {@code values} which is not {@code null}, or - * {@code null} if there are no non-null values - * @since 3.0 - */ - @SafeVarargs - public static T firstNonNull(final T... values) { - if (values != null) { - for (final T val : values) { - if (val != null) { - return val; - } - } - } - return null; - } - - /** - *

- * Executes the given suppliers in order and returns the first return value - * where a value other than {@code null} is returned. Once a non-{@code null} - * value is obtained, all following suppliers are not executed anymore. If all - * the return values are {@code null} or no suppliers are provided then - * {@code null} is returned. - *

- * - *
-	 * ObjectUtils.firstNonNullLazy(null, () -> null) = null
-	 * ObjectUtils.firstNonNullLazy(() -> null, () -> "") = ""
-	 * ObjectUtils.firstNonNullLazy(() -> "", () -> throw new IllegalStateException()) = ""
-	 * ObjectUtils.firstNonNullLazy(() -> null, () -> "zz) = "zz"
-	 * ObjectUtils.firstNonNullLazy() = null
-	 * 
- * - * @param the type of the return values - * @param suppliers the suppliers returning the values to test. {@code null} - * values are ignored. Suppliers may return {@code null} or a - * value of type @{code T} - * @return the first return value from {@code suppliers} which is not - * {@code null}, or {@code null} if there are no non-null values - * @since 3.10 - */ - @SafeVarargs - public static T getFirstNonNull(final Supplier... suppliers) { - if (suppliers != null) { - for (final Supplier supplier : suppliers) { - if (supplier != null) { - final T value = supplier.get(); - if (value != null) { - return value; - } - } - } - } - return null; - } - - /** - *

- * Returns the given {@code object} is it is non-null, otherwise returns the - * Supplier's {@link Supplier#get()} value. - *

- * - *

- * The caller responsible for thread-safety and exception handling of default - * value supplier. - *

- * - *
-	 * ObjectUtils.getIfNull(null, () -> null)     = null
-	 * ObjectUtils.getIfNull(null, null)              = null
-	 * ObjectUtils.getIfNull(null, () -> "")       = ""
-	 * ObjectUtils.getIfNull(null, () -> "zz")     = "zz"
-	 * ObjectUtils.getIfNull("abc", *)                = "abc"
-	 * ObjectUtils.getIfNull(Boolean.TRUE, *)         = Boolean.TRUE
-	 * 
- * - * @param the type of the object - * @param object the {@code Object} to test, may be {@code null} - * @param defaultSupplier the default value to return, may be {@code null} - * @return {@code object} if it is not {@code null}, - * {@code defaultValueSupplier.get()} otherwise - * @since 3.10 - */ - public static T getIfNull(final T object, final Supplier defaultSupplier) { - return object != null ? object : defaultSupplier == null ? null : defaultSupplier.get(); - } - - /** - *

- * Gets the hash code of an object returning zero when the object is - * {@code null}. - *

- * - *
-	 * ObjectUtils.hashCode(null)   = 0
-	 * ObjectUtils.hashCode(obj)    = obj.hashCode()
-	 * 
- * - * @param obj the object to obtain the hash code of, may be {@code null} - * @return the hash code of the object, or zero if null - * @since 2.1 - * @deprecated this method has been replaced by - * {@code java.util.Objects.hashCode(Object)} in Java 7 and will be - * removed in future releases - */ - @Deprecated - public static int hashCode(final Object obj) { - // hashCode(Object) retained for performance, as hash code is often critical - return obj == null ? 0 : obj.hashCode(); - } - - /** - *

- * Gets the hash code for multiple objects. - *

- * - *

- * This allows a hash code to be rapidly calculated for a number of objects. The - * hash code for a single object is the not same as - * {@link #hashCode(Object)}. The hash code for multiple objects is the same as - * that calculated by an {@code ArrayList} containing the specified objects. - *

- * - *
-	 * ObjectUtils.hashCodeMulti()                 = 1
-	 * ObjectUtils.hashCodeMulti((Object[]) null)  = 1
-	 * ObjectUtils.hashCodeMulti(a)                = 31 + a.hashCode()
-	 * ObjectUtils.hashCodeMulti(a,b)              = (31 + a.hashCode()) * 31 + b.hashCode()
-	 * ObjectUtils.hashCodeMulti(a,b,c)            = ((31 + a.hashCode()) * 31 + b.hashCode()) * 31 + c.hashCode()
-	 * 
- * - * @param objects the objects to obtain the hash code of, may be {@code null} - * @return the hash code of the objects, or zero if null - * @since 3.0 - * @deprecated this method has been replaced by - * {@code java.util.Objects.hash(Object...)} in Java 7 and will be - * removed in future releases. - */ - @Deprecated - public static int hashCodeMulti(final Object... objects) { - int hash = 1; - if (objects != null) { - for (final Object object : objects) { - final int tmpHash = hashCode(object); - hash = hash * 31 + tmpHash; - } - } - return hash; - } - - /** - *

- * Appends the toString that would be produced by {@code Object} if a class did - * not override toString itself. {@code null} will throw a NullPointerException - * for either of the two parameters. - *

- * - *
-	 * ObjectUtils.identityToString(appendable, "")            = appendable.append("java.lang.String@1e23"
-	 * ObjectUtils.identityToString(appendable, Boolean.TRUE)  = appendable.append("java.lang.Boolean@7fa"
-	 * ObjectUtils.identityToString(appendable, Boolean.TRUE)  = appendable.append("java.lang.Boolean@7fa")
-	 * 
- * - * @param appendable the appendable to append to - * @param object the object to create a toString for - * @throws IOException if an I/O error occurs. - * @since 3.2 - */ - public static void identityToString(final Appendable appendable, final Object object) throws IOException { - Validate.notNull(object, "object"); - appendable.append(object.getClass().getName()).append(AT_SIGN) - .append(Integer.toHexString(System.identityHashCode(object))); - } - - // Identity ToString - // ----------------------------------------------------------------------- - /** - *

- * Gets the toString that would be produced by {@code Object} if a class did not - * override toString itself. {@code null} will return {@code null}. - *

- * - *
-	 * ObjectUtils.identityToString(null)         = null
-	 * ObjectUtils.identityToString("")           = "java.lang.String@1e23"
-	 * ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
-	 * 
- * - * @param object the object to create a toString for, may be {@code null} - * @return the default toString text, or {@code null} if {@code null} passed in - */ - public static String identityToString(final Object object) { - if (object == null) { - return null; - } - final String name = object.getClass().getName(); - final String hexString = Integer.toHexString(System.identityHashCode(object)); - final StringBuilder builder = new StringBuilder(name.length() + 1 + hexString.length()); - // @formatter:off - builder.append(name) - .append(AT_SIGN) - .append(hexString); - // @formatter:on - return builder.toString(); - } - - /** - *

- * Appends the toString that would be produced by {@code Object} if a class did - * not override toString itself. {@code null} will throw a NullPointerException - * for either of the two parameters. - *

- * - *
-	 * ObjectUtils.identityToString(builder, "")            = builder.append("java.lang.String@1e23"
-	 * ObjectUtils.identityToString(builder, Boolean.TRUE)  = builder.append("java.lang.Boolean@7fa"
-	 * ObjectUtils.identityToString(builder, Boolean.TRUE)  = builder.append("java.lang.Boolean@7fa")
-	 * 
- * - * @param builder the builder to append to - * @param object the object to create a toString for - * @since 3.2 - * @deprecated as of 3.6, because StrBuilder was moved to commons-text, use one - * of the other {@code identityToString} methods instead - */ - @Deprecated - public static void identityToString(final StrBuilder builder, final Object object) { - Validate.notNull(object, "object"); - final String name = object.getClass().getName(); - final String hexString = Integer.toHexString(System.identityHashCode(object)); - builder.ensureCapacity(builder.length() + name.length() + 1 + hexString.length()); - builder.append(name).append(AT_SIGN).append(hexString); - } - - /** - *

- * Appends the toString that would be produced by {@code Object} if a class did - * not override toString itself. {@code null} will throw a NullPointerException - * for either of the two parameters. - *

- * - *
-	 * ObjectUtils.identityToString(buf, "")            = buf.append("java.lang.String@1e23"
-	 * ObjectUtils.identityToString(buf, Boolean.TRUE)  = buf.append("java.lang.Boolean@7fa"
-	 * ObjectUtils.identityToString(buf, Boolean.TRUE)  = buf.append("java.lang.Boolean@7fa")
-	 * 
- * - * @param buffer the buffer to append to - * @param object the object to create a toString for - * @since 2.4 - */ - public static void identityToString(final StringBuffer buffer, final Object object) { - Validate.notNull(object, "object"); - final String name = object.getClass().getName(); - final String hexString = Integer.toHexString(System.identityHashCode(object)); - buffer.ensureCapacity(buffer.length() + name.length() + 1 + hexString.length()); - buffer.append(name).append(AT_SIGN).append(hexString); - } - - /** - *

- * Appends the toString that would be produced by {@code Object} if a class did - * not override toString itself. {@code null} will throw a NullPointerException - * for either of the two parameters. - *

- * - *
-	 * ObjectUtils.identityToString(builder, "")            = builder.append("java.lang.String@1e23"
-	 * ObjectUtils.identityToString(builder, Boolean.TRUE)  = builder.append("java.lang.Boolean@7fa"
-	 * ObjectUtils.identityToString(builder, Boolean.TRUE)  = builder.append("java.lang.Boolean@7fa")
-	 * 
- * - * @param builder the builder to append to - * @param object the object to create a toString for - * @since 3.2 - */ - public static void identityToString(final StringBuilder builder, final Object object) { - Validate.notNull(object, "object"); - final String name = object.getClass().getName(); - final String hexString = Integer.toHexString(System.identityHashCode(object)); - builder.ensureCapacity(builder.length() + name.length() + 1 + hexString.length()); - builder.append(name).append(AT_SIGN).append(hexString); - } - - // Constants (LANG-816): - /* - * These methods ensure constants are not inlined by javac. For example, - * typically a developer might declare a constant like so: - * - * public final static int MAGIC_NUMBER = 5; - * - * Should a different jar file refer to this, and the MAGIC_NUMBER is changed a - * later date (e.g., MAGIC_NUMBER = 6), the different jar file will need to - * recompile itself. This is because javac typically inlines the primitive or - * String constant directly into the bytecode, and removes the reference to the - * MAGIC_NUMBER field. - * - * To help the other jar (so that it does not need to recompile when constants - * are changed) the original developer can declare their constant using one of - * the CONST() utility methods, instead: - * - * public final static int MAGIC_NUMBER = CONST(5); - */ - - // Empty checks - // ----------------------------------------------------------------------- - /** - *

- * Checks if an Object is empty or null. - *

- * - * The following types are supported: - *
    - *
  • {@link CharSequence}: Considered empty if its length is zero.
  • - *
  • {@code Array}: Considered empty if its length is zero.
  • - *
  • {@link Collection}: Considered empty if it has zero elements.
  • - *
  • {@link Map}: Considered empty if it has zero key-value mappings.
  • - *
- * - *
-	 * ObjectUtils.isEmpty(null)             = true
-	 * ObjectUtils.isEmpty("")               = true
-	 * ObjectUtils.isEmpty("ab")             = false
-	 * ObjectUtils.isEmpty(new int[]{})      = true
-	 * ObjectUtils.isEmpty(new int[]{1,2,3}) = false
-	 * ObjectUtils.isEmpty(1234)             = false
-	 * 
- * - * @param object the {@code Object} to test, may be {@code null} - * @return {@code true} if the object has a supported type and is empty or null, - * {@code false} otherwise - * @since 3.9 - */ - public static boolean isEmpty(final Object object) { - if (object == null) { - return true; - } - if (object instanceof CharSequence) { - return ((CharSequence) object).length() == 0; - } - if (object.getClass().isArray()) { - return Array.getLength(object) == 0; - } - if (object instanceof Collection) { - return ((Collection) object).isEmpty(); - } - if (object instanceof Map) { - return ((Map) object).isEmpty(); - } - return false; - } - - /** - *

- * Checks if an Object is not empty and not null. - *

- * - * The following types are supported: - *
    - *
  • {@link CharSequence}: Considered empty if its length is zero.
  • - *
  • {@code Array}: Considered empty if its length is zero.
  • - *
  • {@link Collection}: Considered empty if it has zero elements.
  • - *
  • {@link Map}: Considered empty if it has zero key-value mappings.
  • - *
- * - *
-	 * ObjectUtils.isNotEmpty(null)             = false
-	 * ObjectUtils.isNotEmpty("")               = false
-	 * ObjectUtils.isNotEmpty("ab")             = true
-	 * ObjectUtils.isNotEmpty(new int[]{})      = false
-	 * ObjectUtils.isNotEmpty(new int[]{1,2,3}) = true
-	 * ObjectUtils.isNotEmpty(1234)             = true
-	 * 
- * - * @param object the {@code Object} to test, may be {@code null} - * @return {@code true} if the object has an unsupported type or is not empty - * and not null, {@code false} otherwise - * @since 3.9 - */ - public static boolean isNotEmpty(final Object object) { - return !isEmpty(object); - } - - /** - *

- * Null safe comparison of Comparables. - *

- * - * @param type of the values processed by this method - * @param values the set of comparable values, may be null - * @return - *
    - *
  • If any objects are non-null and unequal, the greater object. - *
  • If all objects are non-null and equal, the first. - *
  • If any of the comparables are null, the greater of the non-null - * objects. - *
  • If all the comparables are null, null is returned. - *
- */ - @SafeVarargs - public static > T max(final T... values) { - T result = null; - if (values != null) { - for (final T value : values) { - if (compare(value, result, false) > 0) { - result = value; - } - } - } - return result; - } - - /** - * Find the "best guess" middle value among comparables. If there is an even - * number of total values, the lower of the two middle values will be returned. - * - * @param type of values processed by this method - * @param comparator to use for comparisons - * @param items to compare - * @return T at middle position - * @throws NullPointerException if items or comparator is {@code null} - * @throws IllegalArgumentException if items is empty or contains {@code null} - * values - * @since 3.0.1 - */ - @SafeVarargs - public static T median(final Comparator comparator, final T... items) { - Validate.notEmpty(items, "null/empty items"); - Validate.noNullElements(items); - Validate.notNull(comparator, "comparator"); - final TreeSet sort = new TreeSet<>(comparator); - Collections.addAll(sort, items); - @SuppressWarnings("unchecked") // we know all items added were T instances - final T result = (T) sort.toArray()[(sort.size() - 1) / 2]; - return result; - } - - /** - * Find the "best guess" middle value among comparables. If there is an even - * number of total values, the lower of the two middle values will be returned. - * - * @param type of values processed by this method - * @param items to compare - * @return T at middle position - * @throws NullPointerException if items is {@code null} - * @throws IllegalArgumentException if items is empty or contains {@code null} - * values - * @since 3.0.1 - */ - @SafeVarargs - public static > T median(final T... items) { - Validate.notEmpty(items); - Validate.noNullElements(items); - final TreeSet sort = new TreeSet<>(); - Collections.addAll(sort, items); - @SuppressWarnings("unchecked") // we know all items added were T instances - final T result = (T) sort.toArray()[(sort.size() - 1) / 2]; - return result; - } - - // Comparable - // ----------------------------------------------------------------------- - /** - *

- * Null safe comparison of Comparables. - *

- * - * @param type of the values processed by this method - * @param values the set of comparable values, may be null - * @return - *
    - *
  • If any objects are non-null and unequal, the lesser object. - *
  • If all objects are non-null and equal, the first. - *
  • If any of the comparables are null, the lesser of the non-null - * objects. - *
  • If all the comparables are null, null is returned. - *
- */ - @SafeVarargs - public static > T min(final T... values) { - T result = null; - if (values != null) { - for (final T value : values) { - if (compare(value, result, true) < 0) { - result = value; - } - } - } - return result; - } - - /** - *

- * Compares two objects for inequality, where either one or both objects may be - * {@code null}. - *

- * - *
-	 * ObjectUtils.notEqual(null, null)                  = false
-	 * ObjectUtils.notEqual(null, "")                    = true
-	 * ObjectUtils.notEqual("", null)                    = true
-	 * ObjectUtils.notEqual("", "")                      = false
-	 * ObjectUtils.notEqual(Boolean.TRUE, null)          = true
-	 * ObjectUtils.notEqual(Boolean.TRUE, "true")        = true
-	 * ObjectUtils.notEqual(Boolean.TRUE, Boolean.TRUE)  = false
-	 * ObjectUtils.notEqual(Boolean.TRUE, Boolean.FALSE) = true
-	 * 
- * - * @param object1 the first object, may be {@code null} - * @param object2 the second object, may be {@code null} - * @return {@code false} if the values of both objects are the same - */ - public static boolean notEqual(final Object object1, final Object object2) { - return !equals(object1, object2); - } - - /** - * Checks that the specified object reference is not {@code null} or empty per - * {@link #isEmpty(Object)}. Use this method for validation, for example: - * - *
- * - *
-	 * public Foo(Bar bar) {
-	 * 	this.bar = Objects.requireNonEmpty(bar);
-	 * }
-	 * 
- * - *
- * - * @param the type of the reference. - * @param obj the object reference to check for nullity. - * @return {@code obj} if not {@code null}. - * @throws NullPointerException if {@code obj} is {@code null}. - * @throws IllegalArgumentException if {@code obj} is empty per - * {@link #isEmpty(Object)}. - * @see #isEmpty(Object) - * @since 3.12.0 - */ - public static T requireNonEmpty(final T obj) { - return requireNonEmpty(obj, "object"); - } - - /** - * Checks that the specified object reference is not {@code null} or empty per - * {@link #isEmpty(Object)}. Use this method for validation, for example: - * - *
- * - *
-	 * public Foo(Bar bar) {
-	 * 	this.bar = Objects.requireNonEmpty(bar, "bar");
-	 * }
-	 * 
- * - *
- * - * @param the type of the reference. - * @param obj the object reference to check for nullity. - * @param message the exception message. - * @return {@code obj} if not {@code null}. - * @throws NullPointerException if {@code obj} is {@code null}. - * @throws IllegalArgumentException if {@code obj} is empty per - * {@link #isEmpty(Object)}. - * @see #isEmpty(Object) - * @since 3.12.0 - */ - public static T requireNonEmpty(final T obj, final String message) { - // check for null first to give the most precise exception. - Objects.requireNonNull(obj, message); - if (isEmpty(obj)) { - throw new IllegalArgumentException(message); - } - return obj; - } - - // ToString - // ----------------------------------------------------------------------- - /** - *

- * Gets the {@code toString} of an {@code Object} returning an empty string ("") - * if {@code null} input. - *

- * - *
-	 * ObjectUtils.toString(null)         = ""
-	 * ObjectUtils.toString("")           = ""
-	 * ObjectUtils.toString("bat")        = "bat"
-	 * ObjectUtils.toString(Boolean.TRUE) = "true"
-	 * 
- * - * @see StringUtils#defaultString(String) - * @see String#valueOf(Object) - * @param obj the Object to {@code toString}, may be null - * @return the passed in Object's toString, or {@code ""} if {@code null} input - * @since 2.0 - * @deprecated this method has been replaced by - * {@code java.util.Objects.toString(Object)} in Java 7 and will be - * removed in future releases. Note however that said method will - * return "null" for null references, while this method returns an - * empty String. To preserve behavior use - * {@code java.util.Objects.toString(myObject, "")} - */ - @Deprecated - public static String toString(final Object obj) { - return obj == null ? StringUtils.EMPTY : obj.toString(); - } - - /** - *

- * Gets the {@code toString} of an {@code Object} returning a specified text if - * {@code null} input. - *

- * - *
-	 * ObjectUtils.toString(null, null)           = null
-	 * ObjectUtils.toString(null, "null")         = "null"
-	 * ObjectUtils.toString("", "null")           = ""
-	 * ObjectUtils.toString("bat", "null")        = "bat"
-	 * ObjectUtils.toString(Boolean.TRUE, "null") = "true"
-	 * 
- * - * @see StringUtils#defaultString(String,String) - * @see String#valueOf(Object) - * @param obj the Object to {@code toString}, may be null - * @param nullStr the String to return if {@code null} input, may be null - * @return the passed in Object's toString, or {@code nullStr} if {@code null} - * input - * @since 2.0 - * @deprecated this method has been replaced by - * {@code java.util.Objects.toString(Object, String)} in Java 7 and - * will be removed in future releases. - */ - @Deprecated - public static String toString(final Object obj, final String nullStr) { - return obj == null ? nullStr : obj.toString(); - } - - /** - *

- * Gets the {@code toString} of an {@code Object} returning a specified text if - * {@code null} input. - *

- * - *
-	 * ObjectUtils.toString(obj, () -> expensive())
-	 * 
- * - *
-	 * ObjectUtils.toString(null, () -> expensive())         = result of expensive()
-	 * ObjectUtils.toString(null, () -> expensive())         = result of expensive()
-	 * ObjectUtils.toString("", () -> expensive())           = ""
-	 * ObjectUtils.toString("bat", () -> expensive())        = "bat"
-	 * ObjectUtils.toString(Boolean.TRUE, () -> expensive()) = "true"
-	 * 
- * - * @param obj the Object to {@code toString}, may be null - * @param supplier the Supplier of String used on {@code null} input, may be - * null - * @return the passed in Object's toString, or {@code nullStr} if {@code null} - * input - * @since 3.11 - */ - public static String toString(final Object obj, final Supplier supplier) { - return obj == null ? supplier == null ? null : supplier.get() : obj.toString(); - } - - /** - * Calls {@link Object#wait(long, int)} for the given Duration. - * - * @param obj The receiver of the wait call. - * @param duration How long to wait. - * @throws IllegalArgumentException if the timeout duration is negative. - * @throws IllegalMonitorStateException if the current thread is not the owner - * of the {@code obj}'s monitor. - * @throws InterruptedException if any thread interrupted the current - * thread before or while the current - * thread was waiting for a notification. - * The interrupted status of the - * current thread is cleared when this - * exception is thrown. - * @see Object#wait(long, int) - * @since 3.12.0 - */ - public static void wait(final Object obj, final Duration duration) throws InterruptedException { - DurationUtils.accept(obj::wait, DurationUtils.zeroIfNull(duration)); - } - - /** - *

- * {@code ObjectUtils} instances should NOT be constructed in standard - * programming. Instead, the static methods on the class should be used, such as - * {@code ObjectUtils.defaultIfNull("a","b");}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public ObjectUtils() { - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/RandomStringUtils.java b/sources/main/java/org/apache/commons/lang3/RandomStringUtils.java deleted file mode 100644 index 4baad6d4..00000000 --- a/sources/main/java/org/apache/commons/lang3/RandomStringUtils.java +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; - -/** - *

- * Generates random {@code String}s. - *

- * - *

- * Caveat: Instances of {@link EaglercraftRandom}, upon which the implementation of this - * class relies, are not cryptographically secure. - *

- * - *

- * RandomStringUtils is intended for simple use cases. For more advanced use - * cases consider using Apache Commons Text's - * RandomStringGenerator instead. - *

- * - *

- * The Apache Commons project provides - * Commons RNG dedicated to - * pseudo-random number generation, that may be a better choice for applications - * with more stringent requirements (performance and/or correctness). - *

- * - *

- * Note that private high surrogate characters are ignored. These are - * Unicode characters that fall between the values 56192 (db80) and 56319 (dbff) - * as we don't know how to handle them. High and low surrogates are correctly - * dealt with - that is if a high surrogate is randomly chosen, 55296 (d800) to - * 56191 (db7f) then it is followed by a low surrogate. If a low surrogate is - * chosen, 56320 (dc00) to 57343 (dfff) then it is placed after a randomly - * chosen high surrogate. - *

- * - *

- * #ThreadSafe# - *

- * - * @since 1.0 - */ -public class RandomStringUtils { - - /** - *

- * Random object used by random method. This has to be not local to the random - * method so as to not return the same value in the same millisecond. - *

- */ - private static final EaglercraftRandom RANDOM = new EaglercraftRandom(); - - /** - *

- * {@code RandomStringUtils} instances should NOT be constructed in standard - * programming. Instead, the class should be used as - * {@code RandomStringUtils.random(5);}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public RandomStringUtils() { - } - - // Random - // ----------------------------------------------------------------------- - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of all characters. - *

- * - * @param count the length of random string to create - * @return the random string - */ - public static String random(final int count) { - return random(count, false, false); - } - - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of characters whose ASCII value is - * between {@code 32} and {@code 126} (inclusive). - *

- * - * @param count the length of random string to create - * @return the random string - */ - public static String randomAscii(final int count) { - return random(count, 32, 127, false, false); - } - - /** - *

- * Creates a random string whose length is between the inclusive minimum and the - * exclusive maximum. - *

- * - *

- * Characters will be chosen from the set of characters whose ASCII value is - * between {@code 32} and {@code 126} (inclusive). - *

- * - * @param minLengthInclusive the inclusive minimum length of the string to - * generate - * @param maxLengthExclusive the exclusive maximum length of the string to - * generate - * @return the random string - * @since 3.5 - */ - public static String randomAscii(final int minLengthInclusive, final int maxLengthExclusive) { - return randomAscii(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); - } - - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of Latin alphabetic characters (a-z, - * A-Z). - *

- * - * @param count the length of random string to create - * @return the random string - */ - public static String randomAlphabetic(final int count) { - return random(count, true, false); - } - - /** - *

- * Creates a random string whose length is between the inclusive minimum and the - * exclusive maximum. - *

- * - *

- * Characters will be chosen from the set of Latin alphabetic characters (a-z, - * A-Z). - *

- * - * @param minLengthInclusive the inclusive minimum length of the string to - * generate - * @param maxLengthExclusive the exclusive maximum length of the string to - * generate - * @return the random string - * @since 3.5 - */ - public static String randomAlphabetic(final int minLengthInclusive, final int maxLengthExclusive) { - return randomAlphabetic(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); - } - - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of Latin alphabetic characters (a-z, - * A-Z) and the digits 0-9. - *

- * - * @param count the length of random string to create - * @return the random string - */ - public static String randomAlphanumeric(final int count) { - return random(count, true, true); - } - - /** - *

- * Creates a random string whose length is between the inclusive minimum and the - * exclusive maximum. - *

- * - *

- * Characters will be chosen from the set of Latin alphabetic characters (a-z, - * A-Z) and the digits 0-9. - *

- * - * @param minLengthInclusive the inclusive minimum length of the string to - * generate - * @param maxLengthExclusive the exclusive maximum length of the string to - * generate - * @return the random string - * @since 3.5 - */ - public static String randomAlphanumeric(final int minLengthInclusive, final int maxLengthExclusive) { - return randomAlphanumeric(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); - } - - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of characters which match the POSIX - * [:graph:] regular expression character class. This class contains all visible - * ASCII characters (i.e. anything except spaces and control characters). - *

- * - * @param count the length of random string to create - * @return the random string - * @since 3.5 - */ - public static String randomGraph(final int count) { - return random(count, 33, 126, false, false); - } - - /** - *

- * Creates a random string whose length is between the inclusive minimum and the - * exclusive maximum. - *

- * - *

- * Characters will be chosen from the set of \p{Graph} characters. - *

- * - * @param minLengthInclusive the inclusive minimum length of the string to - * generate - * @param maxLengthExclusive the exclusive maximum length of the string to - * generate - * @return the random string - * @since 3.5 - */ - public static String randomGraph(final int minLengthInclusive, final int maxLengthExclusive) { - return randomGraph(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); - } - - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of numeric characters. - *

- * - * @param count the length of random string to create - * @return the random string - */ - public static String randomNumeric(final int count) { - return random(count, false, true); - } - - /** - *

- * Creates a random string whose length is between the inclusive minimum and the - * exclusive maximum. - *

- * - *

- * Characters will be chosen from the set of \p{Digit} characters. - *

- * - * @param minLengthInclusive the inclusive minimum length of the string to - * generate - * @param maxLengthExclusive the exclusive maximum length of the string to - * generate - * @return the random string - * @since 3.5 - */ - public static String randomNumeric(final int minLengthInclusive, final int maxLengthExclusive) { - return randomNumeric(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); - } - - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of characters which match the POSIX - * [:print:] regular expression character class. This class includes all visible - * ASCII characters and spaces (i.e. anything except control characters). - *

- * - * @param count the length of random string to create - * @return the random string - * @since 3.5 - */ - public static String randomPrint(final int count) { - return random(count, 32, 126, false, false); - } - - /** - *

- * Creates a random string whose length is between the inclusive minimum and the - * exclusive maximum. - *

- * - *

- * Characters will be chosen from the set of \p{Print} characters. - *

- * - * @param minLengthInclusive the inclusive minimum length of the string to - * generate - * @param maxLengthExclusive the exclusive maximum length of the string to - * generate - * @return the random string - * @since 3.5 - */ - public static String randomPrint(final int minLengthInclusive, final int maxLengthExclusive) { - return randomPrint(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); - } - - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of alpha-numeric characters as - * indicated by the arguments. - *

- * - * @param count the length of random string to create - * @param letters if {@code true}, generated string may include alphabetic - * characters - * @param numbers if {@code true}, generated string may include numeric - * characters - * @return the random string - */ - public static String random(final int count, final boolean letters, final boolean numbers) { - return random(count, 0, 0, letters, numbers); - } - - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of alpha-numeric characters as - * indicated by the arguments. - *

- * - * @param count the length of random string to create - * @param start the position in set of chars to start at - * @param end the position in set of chars to end before - * @param letters if {@code true}, generated string may include alphabetic - * characters - * @param numbers if {@code true}, generated string may include numeric - * characters - * @return the random string - */ - public static String random(final int count, final int start, final int end, final boolean letters, - final boolean numbers) { - return random(count, start, end, letters, numbers, null, RANDOM); - } - - /** - *

- * Creates a random string based on a variety of options, using default source - * of randomness. - *

- * - *

- * This method has exactly the same semantics as - * {@link #random(int,int,int,boolean,boolean,char[],EaglercraftRandom)}, but instead of - * using an externally supplied source of randomness, it uses the internal - * static {@link EaglercraftRandom} instance. - *

- * - * @param count the length of random string to create - * @param start the position in set of chars to start at - * @param end the position in set of chars to end before - * @param letters if {@code true}, generated string may include alphabetic - * characters - * @param numbers if {@code true}, generated string may include numeric - * characters - * @param chars the set of chars to choose randoms from. If {@code null}, then - * it will use the set of all chars. - * @return the random string - * @throws ArrayIndexOutOfBoundsException if there are not - * {@code (end - start) + 1} characters - * in the set array. - */ - public static String random(final int count, final int start, final int end, final boolean letters, - final boolean numbers, final char... chars) { - return random(count, start, end, letters, numbers, chars, RANDOM); - } - - /** - *

- * Creates a random string based on a variety of options, using supplied source - * of randomness. - *

- * - *

- * If start and end are both {@code 0}, start and end are set to {@code ' '} and - * {@code 'z'}, the ASCII printable characters, will be used, unless letters and - * numbers are both {@code false}, in which case, start and end are set to - * {@code 0} and {@link Character#MAX_CODE_POINT}. - * - *

- * If set is not {@code null}, characters between start and end are chosen. - *

- * - *

- * This method accepts a user-supplied {@link EaglercraftRandom} instance to use as a - * source of randomness. By seeding a single {@link EaglercraftRandom} instance with a - * fixed seed and using it for each call, the same random sequence of strings - * can be generated repeatedly and predictably. - *

- * - * @param count the length of random string to create - * @param start the position in set of chars to start at (inclusive) - * @param end the position in set of chars to end before (exclusive) - * @param letters if {@code true}, generated string may include alphabetic - * characters - * @param numbers if {@code true}, generated string may include numeric - * characters - * @param chars the set of chars to choose randoms from, must not be empty. If - * {@code null}, then it will use the set of all chars. - * @param random a source of randomness. - * @return the random string - * @throws ArrayIndexOutOfBoundsException if there are not - * {@code (end - start) + 1} characters - * in the set array. - * @throws IllegalArgumentException if {@code count} < 0 or the - * provided chars array is empty. - * @since 2.0 - */ - public static String random(int count, int start, int end, final boolean letters, final boolean numbers, - final char[] chars, final EaglercraftRandom random) { - if (count == 0) { - return StringUtils.EMPTY; - } else if (count < 0) { - throw new IllegalArgumentException("Requested random string length " + count + " is less than 0."); - } - if (chars != null && chars.length == 0) { - throw new IllegalArgumentException("The chars array must not be empty"); - } - - if (start == 0 && end == 0) { - if (chars != null) { - end = chars.length; - } else if (!letters && !numbers) { - end = Character.MAX_CODE_POINT; - } else { - end = 'z' + 1; - start = ' '; - } - } else if (end <= start) { - throw new IllegalArgumentException( - "Parameter end (" + end + ") must be greater than start (" + start + ")"); - } - - final int zero_digit_ascii = 48; - final int first_letter_ascii = 65; - - if (chars == null && (numbers && end <= zero_digit_ascii || letters && end <= first_letter_ascii)) { - throw new IllegalArgumentException( - "Parameter end (" + end + ") must be greater then (" + zero_digit_ascii + ") for generating digits " - + "or greater then (" + first_letter_ascii + ") for generating letters."); - } - - final StringBuilder builder = new StringBuilder(count); - final int gap = end - start; - - while (count-- != 0) { - final int codePoint; - if (chars == null) { - codePoint = random.nextInt(gap) + start; - - switch (Character.getType(codePoint)) { - case Character.UNASSIGNED: - case Character.PRIVATE_USE: - case Character.SURROGATE: - count++; - continue; - } - - } else { - codePoint = chars[random.nextInt(gap) + start]; - } - - final int numberOfChars = Character.charCount(codePoint); - if (count == 0 && numberOfChars > 1) { - count++; - continue; - } - - if (letters && Character.isLetter(codePoint) || numbers && Character.isDigit(codePoint) - || !letters && !numbers) { - builder.appendCodePoint(codePoint); - - if (numberOfChars == 2) { - count--; - } - - } else { - count++; - } - } - return builder.toString(); - } - - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of characters specified by the string, - * must not be empty. If null, the set of all characters is used. - *

- * - * @param count the length of random string to create - * @param chars the String containing the set of characters to use, may be null, - * but must not be empty - * @return the random string - * @throws IllegalArgumentException if {@code count} < 0 or the string is - * empty. - */ - public static String random(final int count, final String chars) { - if (chars == null) { - return random(count, 0, 0, false, false, null, RANDOM); - } - return random(count, chars.toCharArray()); - } - - /** - *

- * Creates a random string whose length is the number of characters specified. - *

- * - *

- * Characters will be chosen from the set of characters specified. - *

- * - * @param count the length of random string to create - * @param chars the character array containing the set of characters to use, may - * be null - * @return the random string - * @throws IllegalArgumentException if {@code count} < 0. - */ - public static String random(final int count, final char... chars) { - if (chars == null) { - return random(count, 0, 0, false, false, null, RANDOM); - } - return random(count, 0, chars.length, false, false, chars, RANDOM); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/RandomUtils.java b/sources/main/java/org/apache/commons/lang3/RandomUtils.java deleted file mode 100644 index 00a2733a..00000000 --- a/sources/main/java/org/apache/commons/lang3/RandomUtils.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; - -/** - *

- * Utility library that supplements the standard {@link EaglercraftRandom} class. - *

- * - *

- * Caveat: Instances of {@link EaglercraftRandom} are not cryptographically secure. - *

- * - *

- * Please note that the Apache Commons project provides a component dedicated to - * pseudo-random number generation, namely - * Commons RNG, that may be a - * better choice for applications with more stringent requirements (performance - * and/or correctness). - *

- * - * @since 3.3 - */ -public class RandomUtils { - - /** - * Random object used by random method. This has to be not local to the random - * method so as to not return the same value in the same millisecond. - */ - private static final EaglercraftRandom RANDOM = new EaglercraftRandom(); - - /** - *

- * {@code RandomUtils} instances should NOT be constructed in standard - * programming. Instead, the class should be used as - * {@code RandomUtils.nextBytes(5);}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public RandomUtils() { - } - - /** - *

- * Returns a random boolean value - *

- * - * @return the random boolean - * @since 3.5 - */ - public static boolean nextBoolean() { - return RANDOM.nextBoolean(); - } - - /** - *

- * Creates an array of random bytes. - *

- * - * @param count the size of the returned array - * @return the random byte array - * @throws IllegalArgumentException if {@code count} is negative - */ - public static byte[] nextBytes(final int count) { - Validate.isTrue(count >= 0, "Count cannot be negative."); - - final byte[] result = new byte[count]; - RANDOM.nextBytes(result); - return result; - } - - /** - *

- * Returns a random integer within the specified range. - *

- * - * @param startInclusive the smallest value that can be returned, must be - * non-negative - * @param endExclusive the upper bound (not included) - * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or - * if {@code startInclusive} is negative - * @return the random integer - */ - public static int nextInt(final int startInclusive, final int endExclusive) { - Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value."); - Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); - - if (startInclusive == endExclusive) { - return startInclusive; - } - - return startInclusive + RANDOM.nextInt(endExclusive - startInclusive); - } - - /** - *

- * Returns a random int within 0 - Integer.MAX_VALUE - *

- * - * @return the random integer - * @see #nextInt(int, int) - * @since 3.5 - */ - public static int nextInt() { - return nextInt(0, Integer.MAX_VALUE); - } - - /** - *

- * Returns a random long within the specified range. - *

- * - * @param startInclusive the smallest value that can be returned, must be - * non-negative - * @param endExclusive the upper bound (not included) - * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or - * if {@code startInclusive} is negative - * @return the random long - */ - public static long nextLong(final long startInclusive, final long endExclusive) { - Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value."); - Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); - - if (startInclusive == endExclusive) { - return startInclusive; - } - - return startInclusive + nextLong(endExclusive - startInclusive); - } - - /** - *

- * Returns a random long within 0 - Long.MAX_VALUE - *

- * - * @return the random long - * @see #nextLong(long, long) - * @since 3.5 - */ - public static long nextLong() { - return nextLong(Long.MAX_VALUE); - } - - /** - * Generates a {@code long} value between 0 (inclusive) and the specified value - * (exclusive). - * - * @param n Bound on the random number to be returned. Must be positive. - * @return a random {@code long} value between 0 (inclusive) and {@code n} - * (exclusive). - */ - private static long nextLong(final long n) { - // Extracted from o.a.c.rng.core.BaseProvider.nextLong(long) - long bits; - long val; - do { - bits = RANDOM.nextLong() >>> 1; - val = bits % n; - } while (bits - val + (n - 1) < 0); - - return val; - } - - /** - *

- * Returns a random double within the specified range. - *

- * - * @param startInclusive the smallest value that can be returned, must be - * non-negative - * @param endExclusive the upper bound (not included) - * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or - * if {@code startInclusive} is negative - * @return the random double - */ - public static double nextDouble(final double startInclusive, final double endExclusive) { - Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value."); - Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); - - if (startInclusive == endExclusive) { - return startInclusive; - } - - return startInclusive + ((endExclusive - startInclusive) * RANDOM.nextDouble()); - } - - /** - *

- * Returns a random double within 0 - Double.MAX_VALUE - *

- * - * @return the random double - * @see #nextDouble(double, double) - * @since 3.5 - */ - public static double nextDouble() { - return nextDouble(0, Double.MAX_VALUE); - } - - /** - *

- * Returns a random float within the specified range. - *

- * - * @param startInclusive the smallest value that can be returned, must be - * non-negative - * @param endExclusive the upper bound (not included) - * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or - * if {@code startInclusive} is negative - * @return the random float - */ - public static float nextFloat(final float startInclusive, final float endExclusive) { - Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value."); - Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); - - if (startInclusive == endExclusive) { - return startInclusive; - } - - return startInclusive + ((endExclusive - startInclusive) * RANDOM.nextFloat()); - } - - /** - *

- * Returns a random float within 0 - Float.MAX_VALUE - *

- * - * @return the random float - * @see #nextFloat(float, float) - * @since 3.5 - */ - public static float nextFloat() { - return nextFloat(0, Float.MAX_VALUE); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/Range.java b/sources/main/java/org/apache/commons/lang3/Range.java deleted file mode 100644 index 757bb3ed..00000000 --- a/sources/main/java/org/apache/commons/lang3/Range.java +++ /dev/null @@ -1,616 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.io.Serializable; -import java.util.Comparator; - -import net.lax1dude.eaglercraft.v1_8.HString; - -/** - *

- * An immutable range of objects from a minimum to maximum point inclusive. - *

- * - *

- * The objects need to either be implementations of {@code Comparable} or you - * need to supply a {@code Comparator}. - *

- * - *

- * #ThreadSafe# if the objects and comparator are thread-safe - *

- * - * @param The type of range values. - * @since 3.0 - */ -public final class Range implements Serializable { - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private enum ComparableComparator implements Comparator { - INSTANCE; - - /** - * Comparable based compare implementation. - * - * @param obj1 left hand side of comparison - * @param obj2 right hand side of comparison - * @return negative, 0, positive comparison value - */ - @Override - public int compare(final Object obj1, final Object obj2) { - return ((Comparable) obj1).compareTo(obj2); - } - } - - /** - * Serialization version. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 1L; - - /** - *

- * Obtains a range with the specified minimum and maximum values (both - * inclusive). - *

- * - *

- * The range uses the natural ordering of the elements to determine where values - * lie in the range. - *

- * - *

- * The arguments may be passed in the order (min,max) or (max,min). The - * getMinimum and getMaximum methods will return the correct values. - *

- * - * @param the type of the elements in this range - * @param fromInclusive the first value that defines the edge of the range, - * inclusive - * @param toInclusive the second value that defines the edge of the range, - * inclusive - * @return the range object, not null - * @throws IllegalArgumentException if either element is null - * @throws ClassCastException if the elements are not {@code Comparable} - */ - public static > Range between(final T fromInclusive, final T toInclusive) { - return between(fromInclusive, toInclusive, null); - } - - /** - *

- * Obtains a range with the specified minimum and maximum values (both - * inclusive). - *

- * - *

- * The range uses the specified {@code Comparator} to determine where values lie - * in the range. - *

- * - *

- * The arguments may be passed in the order (min,max) or (max,min). The - * getMinimum and getMaximum methods will return the correct values. - *

- * - * @param the type of the elements in this range - * @param fromInclusive the first value that defines the edge of the range, - * inclusive - * @param toInclusive the second value that defines the edge of the range, - * inclusive - * @param comparator the comparator to be used, null for natural ordering - * @return the range object, not null - * @throws IllegalArgumentException if either element is null - * @throws ClassCastException if using natural ordering and the elements - * are not {@code Comparable} - */ - public static Range between(final T fromInclusive, final T toInclusive, final Comparator comparator) { - return new Range<>(fromInclusive, toInclusive, comparator); - } - - /** - *

- * Obtains a range using the specified element as both the minimum and maximum - * in this range. - *

- * - *

- * The range uses the natural ordering of the elements to determine where values - * lie in the range. - *

- * - * @param the type of the elements in this range - * @param element the value to use for this range, not null - * @return the range object, not null - * @throws IllegalArgumentException if the element is null - * @throws ClassCastException if the element is not {@code Comparable} - */ - public static > Range is(final T element) { - return between(element, element, null); - } - - /** - *

- * Obtains a range using the specified element as both the minimum and maximum - * in this range. - *

- * - *

- * The range uses the specified {@code Comparator} to determine where values lie - * in the range. - *

- * - * @param the type of the elements in this range - * @param element the value to use for this range, must not be {@code null} - * @param comparator the comparator to be used, null for natural ordering - * @return the range object, not null - * @throws IllegalArgumentException if the element is null - * @throws ClassCastException if using natural ordering and the elements - * are not {@code Comparable} - */ - public static Range is(final T element, final Comparator comparator) { - return between(element, element, comparator); - } - - /** - * The ordering scheme used in this range. - */ - private final Comparator comparator; - - /** - * Cached output hashCode (class is immutable). - */ - private transient int hashCode; - - /** - * The maximum value in this range (inclusive). - */ - private final T maximum; - - /** - * The minimum value in this range (inclusive). - */ - private final T minimum; - - /** - * Cached output toString (class is immutable). - */ - private transient String toString; - - /** - * Creates an instance. - * - * @param element1 the first element, not null - * @param element2 the second element, not null - * @param comp the comparator to be used, null for natural ordering - */ - @SuppressWarnings("unchecked") - private Range(final T element1, final T element2, final Comparator comp) { - if (element1 == null || element2 == null) { - throw new IllegalArgumentException( - "Elements in a range must not be null: element1=" + element1 + ", element2=" + element2); - } - if (comp == null) { - this.comparator = ComparableComparator.INSTANCE; - } else { - this.comparator = comp; - } - if (this.comparator.compare(element1, element2) < 1) { - this.minimum = element1; - this.maximum = element2; - } else { - this.minimum = element2; - this.maximum = element1; - } - } - - /** - *

- * Checks whether the specified element occurs within this range. - *

- * - * @param element the element to check for, null returns false - * @return true if the specified element occurs within this range - */ - public boolean contains(final T element) { - if (element == null) { - return false; - } - return comparator.compare(element, minimum) > -1 && comparator.compare(element, maximum) < 1; - } - - /** - *

- * Checks whether this range contains all the elements of the specified range. - *

- * - *

- * This method may fail if the ranges have two different comparators or element - * types. - *

- * - * @param otherRange the range to check, null returns false - * @return true if this range contains the specified range - * @throws RuntimeException if ranges cannot be compared - */ - public boolean containsRange(final Range otherRange) { - if (otherRange == null) { - return false; - } - return contains(otherRange.minimum) && contains(otherRange.maximum); - } - - /** - *

- * Checks where the specified element occurs relative to this range. - *

- * - *

- * The API is reminiscent of the Comparable interface returning {@code -1} if - * the element is before the range, {@code 0} if contained within the range and - * {@code 1} if the element is after the range. - *

- * - * @param element the element to check for, not null - * @return -1, 0 or +1 depending on the element's location relative to the range - */ - public int elementCompareTo(final T element) { - // Comparable API says throw NPE on null - Validate.notNull(element, "element"); - if (isAfter(element)) { - return -1; - } else if (isBefore(element)) { - return 1; - } else { - return 0; - } - } - - // Element tests - // -------------------------------------------------------------------- - - /** - *

- * Compares this range to another object to test if they are equal. - *

- * . - * - *

- * To be equal, the minimum and maximum values must be equal, which ignores any - * differences in the comparator. - *

- * - * @param obj the reference object with which to compare - * @return true if this object is equal - */ - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } else if (obj == null || obj.getClass() != getClass()) { - return false; - } else { - @SuppressWarnings("unchecked") // OK because we checked the class above - final Range range = (Range) obj; - return minimum.equals(range.minimum) && maximum.equals(range.maximum); - } - } - - /** - *

- * Gets the comparator being used to determine if objects are within the range. - *

- * - *

- * Natural ordering uses an internal comparator implementation, thus this method - * never returns null. See {@link #isNaturalOrdering()}. - *

- * - * @return the comparator being used, not null - */ - public Comparator getComparator() { - return comparator; - } - - /** - *

- * Gets the maximum value in this range. - *

- * - * @return the maximum value in this range, not null - */ - public T getMaximum() { - return maximum; - } - - /** - *

- * Gets the minimum value in this range. - *

- * - * @return the minimum value in this range, not null - */ - public T getMinimum() { - return minimum; - } - - /** - *

- * Gets a suitable hash code for the range. - *

- * - * @return a hash code value for this object - */ - @Override - public int hashCode() { - int result = hashCode; - if (hashCode == 0) { - result = 17; - result = 37 * result + getClass().hashCode(); - result = 37 * result + minimum.hashCode(); - result = 37 * result + maximum.hashCode(); - hashCode = result; - } - return result; - } - - /** - * Calculate the intersection of {@code this} and an overlapping Range. - * - * @param other overlapping Range - * @return range representing the intersection of {@code this} and {@code other} - * ({@code this} if equal) - * @throws IllegalArgumentException if {@code other} does not overlap - * {@code this} - * @since 3.0.1 - */ - public Range intersectionWith(final Range other) { - if (!this.isOverlappedBy(other)) { - throw new IllegalArgumentException( - HString.format("Cannot calculate intersection with non-overlapping range %s", other)); - } - if (this.equals(other)) { - return this; - } - final T min = getComparator().compare(minimum, other.minimum) < 0 ? other.minimum : minimum; - final T max = getComparator().compare(maximum, other.maximum) < 0 ? maximum : other.maximum; - return between(min, max, getComparator()); - } - - /** - *

- * Checks whether this range is after the specified element. - *

- * - * @param element the element to check for, null returns false - * @return true if this range is entirely after the specified element - */ - public boolean isAfter(final T element) { - if (element == null) { - return false; - } - return comparator.compare(element, minimum) < 0; - } - - /** - *

- * Checks whether this range is completely after the specified range. - *

- * - *

- * This method may fail if the ranges have two different comparators or element - * types. - *

- * - * @param otherRange the range to check, null returns false - * @return true if this range is completely after the specified range - * @throws RuntimeException if ranges cannot be compared - */ - public boolean isAfterRange(final Range otherRange) { - if (otherRange == null) { - return false; - } - return isAfter(otherRange.maximum); - } - - /** - *

- * Checks whether this range is before the specified element. - *

- * - * @param element the element to check for, null returns false - * @return true if this range is entirely before the specified element - */ - public boolean isBefore(final T element) { - if (element == null) { - return false; - } - return comparator.compare(element, maximum) > 0; - } - - /** - *

- * Checks whether this range is completely before the specified range. - *

- * - *

- * This method may fail if the ranges have two different comparators or element - * types. - *

- * - * @param otherRange the range to check, null returns false - * @return true if this range is completely before the specified range - * @throws RuntimeException if ranges cannot be compared - */ - public boolean isBeforeRange(final Range otherRange) { - if (otherRange == null) { - return false; - } - return isBefore(otherRange.minimum); - } - - /** - *

- * Checks whether this range ends with the specified element. - *

- * - * @param element the element to check for, null returns false - * @return true if the specified element occurs within this range - */ - public boolean isEndedBy(final T element) { - if (element == null) { - return false; - } - return comparator.compare(element, maximum) == 0; - } - - /** - *

- * Whether or not the Range is using the natural ordering of the elements. - *

- * - *

- * Natural ordering uses an internal comparator implementation, thus this method - * is the only way to check if a null comparator was specified. - *

- * - * @return true if using natural ordering - */ - public boolean isNaturalOrdering() { - return comparator == ComparableComparator.INSTANCE; - } - - /** - *

- * Checks whether this range is overlapped by the specified range. - *

- * - *

- * Two ranges overlap if there is at least one element in common. - *

- * - *

- * This method may fail if the ranges have two different comparators or element - * types. - *

- * - * @param otherRange the range to test, null returns false - * @return true if the specified range overlaps with this range; otherwise, - * {@code false} - * @throws RuntimeException if ranges cannot be compared - */ - public boolean isOverlappedBy(final Range otherRange) { - if (otherRange == null) { - return false; - } - return otherRange.contains(minimum) || otherRange.contains(maximum) || contains(otherRange.minimum); - } - - /** - *

- * Checks whether this range starts with the specified element. - *

- * - * @param element the element to check for, null returns false - * @return true if the specified element occurs within this range - */ - public boolean isStartedBy(final T element) { - if (element == null) { - return false; - } - return comparator.compare(element, minimum) == 0; - } - - /** - *

- * Fits the given element into this range by returning the given element or, if - * out of bounds, the range minimum if below, or the range maximum if above. - *

- * - *
-	 * Range<Integer> range = Range.between(16, 64);
-	 * range.fit(-9) -->  16
-	 * range.fit(0)  -->  16
-	 * range.fit(15) -->  16
-	 * range.fit(16) -->  16
-	 * range.fit(17) -->  17
-	 * ...
-	 * range.fit(63) -->  63
-	 * range.fit(64) -->  64
-	 * range.fit(99) -->  64
-	 * 
- * - * @param element the element to check for, not null - * @return the minimum, the element, or the maximum depending on the element's - * location relative to the range - * @since 3.10 - */ - public T fit(final T element) { - // Comparable API says throw NPE on null - Validate.notNull(element, "element"); - if (isAfter(element)) { - return minimum; - } else if (isBefore(element)) { - return maximum; - } else { - return element; - } - } - - /** - *

- * Gets the range as a {@code String}. - *

- * - *

- * The format of the String is '[min..max]'. - *

- * - * @return the {@code String} representation of this range - */ - @Override - public String toString() { - if (toString == null) { - toString = "[" + minimum + ".." + maximum + "]"; - } - return toString; - } - - /** - *

- * Formats the receiver using the given format. - *

- * - *

- * This uses {@link java.util.Formattable} to perform the formatting. Three - * variables may be used to embed the minimum, maximum and comparator. Use - * {@code %1$s} for the minimum element, {@code %2$s} for the maximum element - * and {@code %3$s} for the comparator. The default format used by - * {@code toString()} is {@code [%1$s..%2$s]}. - *

- * - * @param format the format string, optionally containing {@code %1$s}, - * {@code %2$s} and {@code %3$s}, not null - * @return the formatted string, not null - */ - public String toString(final String format) { - return HString.format(format, minimum, maximum, comparator); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/RegExUtils.java b/sources/main/java/org/apache/commons/lang3/RegExUtils.java deleted file mode 100644 index 50f20f8b..00000000 --- a/sources/main/java/org/apache/commons/lang3/RegExUtils.java +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.util.regex.Pattern; - -/** - *

- * Helpers to process Strings using regular expressions. - *

- * - * @see java.util.regex.Pattern - * @since 3.8 - */ -public class RegExUtils { - - /** - *

- * Removes each substring of the text String that matches the given regular - * expression pattern. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code pattern.matcher(text).replaceAll(StringUtils.EMPTY)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.removeAll(null, *)      = null
-	 * StringUtils.removeAll("any", (Pattern) null)  = "any"
-	 * StringUtils.removeAll("any", Pattern.compile(""))    = "any"
-	 * StringUtils.removeAll("any", Pattern.compile(".*"))  = ""
-	 * StringUtils.removeAll("any", Pattern.compile(".+"))  = ""
-	 * StringUtils.removeAll("abc", Pattern.compile(".?"))  = ""
-	 * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\nB"
-	 * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
-	 * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>", Pattern.DOTALL))  = "AB"
-	 * StringUtils.removeAll("ABCabc123abc", Pattern.compile("[a-z]"))     = "ABC123"
-	 * 
- * - * @param text text to remove from, may be null - * @param regex the regular expression to which this string is to be matched - * @return the text with any removes processed, {@code null} if null String - * input - * - * @see #replaceAll(String, Pattern, String) - * @see java.util.regex.Matcher#replaceAll(String) - * @see java.util.regex.Pattern - */ - public static String removeAll(final String text, final Pattern regex) { - return replaceAll(text, regex, StringUtils.EMPTY); - } - - /** - *

- * Removes each substring of the text String that matches the given regular - * expression. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code text.replaceAll(regex, StringUtils.EMPTY)}
  • - *
  • {@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *

- * Unlike in the {@link #removePattern(String, String)} method, the - * {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL - * option prepend {@code "(?s)"} to the regex. DOTALL is also known as - * single-line mode in Perl. - *

- * - *
-	 * StringUtils.removeAll(null, *)      = null
-	 * StringUtils.removeAll("any", (String) null)  = "any"
-	 * StringUtils.removeAll("any", "")    = "any"
-	 * StringUtils.removeAll("any", ".*")  = ""
-	 * StringUtils.removeAll("any", ".+")  = ""
-	 * StringUtils.removeAll("abc", ".?")  = ""
-	 * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
-	 * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
-	 * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
-	 * 
- * - * @param text text to remove from, may be null - * @param regex the regular expression to which this string is to be matched - * @return the text with any removes processed, {@code null} if null String - * input - * - * @throws java.util.regex.PatternSyntaxException if the regular expression's - * syntax is invalid - * - * @see #replaceAll(String, String, String) - * @see #removePattern(String, String) - * @see String#replaceAll(String, String) - * @see java.util.regex.Pattern - * @see java.util.regex.Pattern#DOTALL - */ - public static String removeAll(final String text, final String regex) { - return replaceAll(text, regex, StringUtils.EMPTY); - } - - /** - *

- * Removes the first substring of the text string that matches the given regular - * expression pattern. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code pattern.matcher(text).replaceFirst(StringUtils.EMPTY)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.removeFirst(null, *)      = null
-	 * StringUtils.removeFirst("any", (Pattern) null)  = "any"
-	 * StringUtils.removeFirst("any", Pattern.compile(""))    = "any"
-	 * StringUtils.removeFirst("any", Pattern.compile(".*"))  = ""
-	 * StringUtils.removeFirst("any", Pattern.compile(".+"))  = ""
-	 * StringUtils.removeFirst("abc", Pattern.compile(".?"))  = "bc"
-	 * StringUtils.removeFirst("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\n<__>B"
-	 * StringUtils.removeFirst("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
-	 * StringUtils.removeFirst("ABCabc123", Pattern.compile("[a-z]"))          = "ABCbc123"
-	 * StringUtils.removeFirst("ABCabc123abc", Pattern.compile("[a-z]+"))      = "ABC123abc"
-	 * 
- * - * @param text text to remove from, may be null - * @param regex the regular expression pattern to which this string is to be - * matched - * @return the text with the first replacement processed, {@code null} if null - * String input - * - * @see #replaceFirst(String, Pattern, String) - * @see java.util.regex.Matcher#replaceFirst(String) - * @see java.util.regex.Pattern - */ - public static String removeFirst(final String text, final Pattern regex) { - return replaceFirst(text, regex, StringUtils.EMPTY); - } - - /** - *

- * Removes the first substring of the text string that matches the given regular - * expression. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code text.replaceFirst(regex, StringUtils.EMPTY)}
  • - *
  • {@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *

- * The {@link Pattern#DOTALL} option is NOT automatically added. To use the - * DOTALL option prepend {@code "(?s)"} to the regex. DOTALL is also known as - * single-line mode in Perl. - *

- * - *
-	 * StringUtils.removeFirst(null, *)      = null
-	 * StringUtils.removeFirst("any", (String) null)  = "any"
-	 * StringUtils.removeFirst("any", "")    = "any"
-	 * StringUtils.removeFirst("any", ".*")  = ""
-	 * StringUtils.removeFirst("any", ".+")  = ""
-	 * StringUtils.removeFirst("abc", ".?")  = "bc"
-	 * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
-	 * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
-	 * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
-	 * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
-	 * 
- * - * @param text text to remove from, may be null - * @param regex the regular expression to which this string is to be matched - * @return the text with the first replacement processed, {@code null} if null - * String input - * - * @throws java.util.regex.PatternSyntaxException if the regular expression's - * syntax is invalid - * - * @see #replaceFirst(String, String, String) - * @see String#replaceFirst(String, String) - * @see java.util.regex.Pattern - * @see java.util.regex.Pattern#DOTALL - */ - public static String removeFirst(final String text, final String regex) { - return replaceFirst(text, regex, StringUtils.EMPTY); - } - - /** - *

- * Removes each substring of the source String that matches the given regular - * expression using the DOTALL option. - *

- * - * This call is a {@code null} safe equivalent to: - *
    - *
  • {@code text.replaceAll("(?s)" + regex, StringUtils.EMPTY)}
  • - *
  • {@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(StringUtils.EMPTY)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.removePattern(null, *)       = null
-	 * StringUtils.removePattern("any", (String) null)   = "any"
-	 * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
-	 * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
-	 * 
- * - * @param text the source string - * @param regex the regular expression to which this string is to be matched - * @return The resulting {@code String} - * @see #replacePattern(String, String, String) - * @see String#replaceAll(String, String) - * @see Pattern#DOTALL - */ - public static String removePattern(final String text, final String regex) { - return replacePattern(text, regex, StringUtils.EMPTY); - } - - /** - *

- * Replaces each substring of the text String that matches the given regular - * expression pattern with the given replacement. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code pattern.matcher(text).replaceAll(replacement)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replaceAll(null, *, *)       = null
-	 * StringUtils.replaceAll("any", (Pattern) null, *)   = "any"
-	 * StringUtils.replaceAll("any", *, null)   = "any"
-	 * StringUtils.replaceAll("", Pattern.compile(""), "zzz")    = "zzz"
-	 * StringUtils.replaceAll("", Pattern.compile(".*"), "zzz")  = "zzz"
-	 * StringUtils.replaceAll("", Pattern.compile(".+"), "zzz")  = ""
-	 * StringUtils.replaceAll("abc", Pattern.compile(""), "ZZ")  = "ZZaZZbZZcZZ"
-	 * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>"), "z")                 = "z\nz"
-	 * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>", Pattern.DOTALL), "z") = "z"
-	 * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")             = "z"
-	 * StringUtils.replaceAll("ABCabc123", Pattern.compile("[a-z]"), "_")       = "ABC___123"
-	 * StringUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123"
-	 * StringUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123"
-	 * StringUtils.replaceAll("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum_dolor_sit"
-	 * 
- * - * @param text text to search and replace in, may be null - * @param regex the regular expression pattern to which this string is to - * be matched - * @param replacement the string to be substituted for each match - * @return the text with any replacements processed, {@code null} if null String - * input - * - * @see java.util.regex.Matcher#replaceAll(String) - * @see java.util.regex.Pattern - */ - public static String replaceAll(final String text, final Pattern regex, final String replacement) { - if (ObjectUtils.anyNull(text, regex, replacement)) { - return text; - } - return regex.matcher(text).replaceAll(replacement); - } - - /** - *

- * Replaces each substring of the text String that matches the given regular - * expression with the given replacement. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code text.replaceAll(regex, replacement)}
  • - *
  • {@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *

- * Unlike in the {@link #replacePattern(String, String, String)} method, the - * {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL - * option prepend {@code "(?s)"} to the regex. DOTALL is also known as - * single-line mode in Perl. - *

- * - *
-	 * StringUtils.replaceAll(null, *, *)       = null
-	 * StringUtils.replaceAll("any", (String) null, *)   = "any"
-	 * StringUtils.replaceAll("any", *, null)   = "any"
-	 * StringUtils.replaceAll("", "", "zzz")    = "zzz"
-	 * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
-	 * StringUtils.replaceAll("", ".+", "zzz")  = ""
-	 * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
-	 * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")      = "z\nz"
-	 * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")  = "z"
-	 * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
-	 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
-	 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
-	 * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
-	 * 
- * - * @param text text to search and replace in, may be null - * @param regex the regular expression to which this string is to be - * matched - * @param replacement the string to be substituted for each match - * @return the text with any replacements processed, {@code null} if null String - * input - * - * @throws java.util.regex.PatternSyntaxException if the regular expression's - * syntax is invalid - * - * @see #replacePattern(String, String, String) - * @see String#replaceAll(String, String) - * @see java.util.regex.Pattern - * @see java.util.regex.Pattern#DOTALL - */ - public static String replaceAll(final String text, final String regex, final String replacement) { - if (ObjectUtils.anyNull(text, regex, replacement)) { - return text; - } - return text.replaceAll(regex, replacement); - } - - /** - *

- * Replaces the first substring of the text string that matches the given - * regular expression pattern with the given replacement. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code pattern.matcher(text).replaceFirst(replacement)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replaceFirst(null, *, *)       = null
-	 * StringUtils.replaceFirst("any", (Pattern) null, *)   = "any"
-	 * StringUtils.replaceFirst("any", *, null)   = "any"
-	 * StringUtils.replaceFirst("", Pattern.compile(""), "zzz")    = "zzz"
-	 * StringUtils.replaceFirst("", Pattern.compile(".*"), "zzz")  = "zzz"
-	 * StringUtils.replaceFirst("", Pattern.compile(".+"), "zzz")  = ""
-	 * StringUtils.replaceFirst("abc", Pattern.compile(""), "ZZ")  = "ZZabc"
-	 * StringUtils.replaceFirst("<__>\n<__>", Pattern.compile("<.*>"), "z")      = "z\n<__>"
-	 * StringUtils.replaceFirst("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")  = "z"
-	 * StringUtils.replaceFirst("ABCabc123", Pattern.compile("[a-z]"), "_")          = "ABC_bc123"
-	 * StringUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123abc"
-	 * StringUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123abc"
-	 * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum  dolor   sit"
-	 * 
- * - * @param text text to search and replace in, may be null - * @param regex the regular expression pattern to which this string is to - * be matched - * @param replacement the string to be substituted for the first match - * @return the text with the first replacement processed, {@code null} if null - * String input - * - * @see java.util.regex.Matcher#replaceFirst(String) - * @see java.util.regex.Pattern - */ - public static String replaceFirst(final String text, final Pattern regex, final String replacement) { - if (text == null || regex == null || replacement == null) { - return text; - } - return regex.matcher(text).replaceFirst(replacement); - } - - /** - *

- * Replaces the first substring of the text string that matches the given - * regular expression with the given replacement. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code text.replaceFirst(regex, replacement)}
  • - *
  • {@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *

- * The {@link Pattern#DOTALL} option is NOT automatically added. To use the - * DOTALL option prepend {@code "(?s)"} to the regex. DOTALL is also known as - * single-line mode in Perl. - *

- * - *
-	 * StringUtils.replaceFirst(null, *, *)       = null
-	 * StringUtils.replaceFirst("any", (String) null, *)   = "any"
-	 * StringUtils.replaceFirst("any", *, null)   = "any"
-	 * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
-	 * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
-	 * StringUtils.replaceFirst("", ".+", "zzz")  = ""
-	 * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
-	 * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
-	 * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
-	 * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
-	 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
-	 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
-	 * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
-	 * 
- * - * @param text text to search and replace in, may be null - * @param regex the regular expression to which this string is to be - * matched - * @param replacement the string to be substituted for the first match - * @return the text with the first replacement processed, {@code null} if null - * String input - * - * @throws java.util.regex.PatternSyntaxException if the regular expression's - * syntax is invalid - * - * @see String#replaceFirst(String, String) - * @see java.util.regex.Pattern - * @see java.util.regex.Pattern#DOTALL - */ - public static String replaceFirst(final String text, final String regex, final String replacement) { - if (text == null || regex == null || replacement == null) { - return text; - } - return text.replaceFirst(regex, replacement); - } - - /** - *

- * Replaces each substring of the source String that matches the given regular - * expression with the given replacement using the {@link Pattern#DOTALL} - * option. DOTALL is also known as single-line mode in Perl. - *

- * - * This call is a {@code null} safe equivalent to: - *
    - *
  • {@code text.replaceAll("(?s)" + regex, replacement)}
  • - *
  • {@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(replacement)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replacePattern(null, *, *)       = null
-	 * StringUtils.replacePattern("any", (String) null, *)   = "any"
-	 * StringUtils.replacePattern("any", *, null)   = "any"
-	 * StringUtils.replacePattern("", "", "zzz")    = "zzz"
-	 * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
-	 * StringUtils.replacePattern("", ".+", "zzz")  = ""
-	 * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
-	 * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
-	 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
-	 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
-	 * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
-	 * 
- * - * @param text the source string - * @param regex the regular expression to which this string is to be - * matched - * @param replacement the string to be substituted for each match - * @return The resulting {@code String} - * @see #replaceAll(String, String, String) - * @see String#replaceAll(String, String) - * @see Pattern#DOTALL - */ - public static String replacePattern(final String text, final String regex, final String replacement) { - if (ObjectUtils.anyNull(text, regex, replacement)) { - return text; - } - return Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(replacement); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/SerializationException.java b/sources/main/java/org/apache/commons/lang3/SerializationException.java deleted file mode 100644 index e31e3b69..00000000 --- a/sources/main/java/org/apache/commons/lang3/SerializationException.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -/** - *

- * Exception thrown when the Serialization process fails. - *

- * - *

- * The original error is wrapped within this one. - *

- * - *

- * #NotThreadSafe# because Throwable is not thread-safe - *

- * - * @since 1.0 - */ -public class SerializationException extends RuntimeException { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 4029025366392702726L; - - /** - *

- * Constructs a new {@code SerializationException} without specified detail - * message. - *

- */ - public SerializationException() { - } - - /** - *

- * Constructs a new {@code SerializationException} with specified detail - * message. - *

- * - * @param msg The error message. - */ - public SerializationException(final String msg) { - super(msg); - } - - /** - *

- * Constructs a new {@code SerializationException} with specified nested - * {@code Throwable}. - *

- * - * @param cause The {@code Exception} or {@code Error} that caused this - * exception to be thrown. - */ - public SerializationException(final Throwable cause) { - super(cause); - } - - /** - *

- * Constructs a new {@code SerializationException} with specified detail message - * and nested {@code Throwable}. - *

- * - * @param msg The error message. - * @param cause The {@code Exception} or {@code Error} that caused this - * exception to be thrown. - */ - public SerializationException(final String msg, final Throwable cause) { - super(msg, cause); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/SerializationUtils.java b/sources/main/java/org/apache/commons/lang3/SerializationUtils.java deleted file mode 100644 index 009a389d..00000000 --- a/sources/main/java/org/apache/commons/lang3/SerializationUtils.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.ObjectStreamClass; -import java.io.OutputStream; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import net.lax1dude.eaglercraft.v1_8.EaglerInputStream; - -/** - *

- * Assists with the serialization process and performs additional functionality - * based on serialization. - *

- * - *
    - *
  • Deep clone using serialization - *
  • Serialize managing finally and IOException - *
  • Deserialize managing finally and IOException - *
- * - *

- * This class throws exceptions for invalid {@code null} inputs. Each method - * documents its behavior in more detail. - *

- * - *

- * #ThreadSafe# - *

- * - * @since 1.0 - */ -public class SerializationUtils { - - /** - *

- * Custom specialization of the standard JDK {@link java.io.ObjectInputStream} - * that uses a custom {@code ClassLoader} to resolve a class. If the specified - * {@code ClassLoader} is not able to resolve the class, the context classloader - * of the current thread will be used. This way, the standard deserialization - * work also in web-application containers and application servers, no matter in - * which of the {@code ClassLoader} the particular class that encapsulates - * serialization/deserialization lives. - *

- * - *

- * For more in-depth information about the problem for which this class here is - * a workaround, see the JIRA issue LANG-626. - *

- */ - static class ClassLoaderAwareObjectInputStream extends ObjectInputStream { - private static final Map> primitiveTypes = new HashMap<>(); - - static { - primitiveTypes.put("byte", byte.class); - primitiveTypes.put("short", short.class); - primitiveTypes.put("int", int.class); - primitiveTypes.put("long", long.class); - primitiveTypes.put("float", float.class); - primitiveTypes.put("double", double.class); - primitiveTypes.put("boolean", boolean.class); - primitiveTypes.put("char", char.class); - primitiveTypes.put("void", void.class); - } - - private final ClassLoader classLoader; - - /** - * Constructor. - * - * @param in The {@code InputStream}. - * @param classLoader classloader to use - * @throws IOException if an I/O error occurs while reading stream header. - * @see java.io.ObjectInputStream - */ - ClassLoaderAwareObjectInputStream(final InputStream in, final ClassLoader classLoader) throws IOException { - super(in); - this.classLoader = classLoader; - } - - /** - * Overridden version that uses the parameterized {@code ClassLoader} or the - * {@code ClassLoader} of the current {@code Thread} to resolve the class. - * - * @param desc An instance of class {@code ObjectStreamClass}. - * @return A {@code Class} object corresponding to {@code desc}. - * @throws IOException Any of the usual Input/Output exceptions. - * @throws ClassNotFoundException If class of a serialized object cannot be - * found. - */ - @Override - protected Class resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException { - final String name = desc.getName(); - try { - return Class.forName(name, false, classLoader); - } catch (final ClassNotFoundException ex) { - try { - return Class.forName(name, false, Thread.currentThread().getContextClassLoader()); - } catch (final ClassNotFoundException cnfe) { - final Class cls = primitiveTypes.get(name); - if (cls != null) { - return cls; - } - throw cnfe; - } - } - } - - } - - /** - *

- * Deep clone an {@code Object} using serialization. - *

- * - *

- * This is many times slower than writing clone methods by hand on all objects - * in your object graph. However, for complex object graphs, or for those that - * don't support deep cloning this can be a simple alternative implementation. - * Of course all the objects must be {@code Serializable}. - *

- * - * @param the type of the object involved - * @param object the {@code Serializable} object to clone - * @return the cloned object - * @throws SerializationException (runtime) if the serialization fails - */ - public static T clone(final T object) { - if (object == null) { - return null; - } - final byte[] objectData = serialize(object); - final EaglerInputStream bais = new EaglerInputStream(objectData); - - try (ClassLoaderAwareObjectInputStream in = new ClassLoaderAwareObjectInputStream(bais, - object.getClass().getClassLoader())) { - /* - * when we serialize and deserialize an object, it is reasonable to assume the - * deserialized object is of the same type as the original serialized object - */ - @SuppressWarnings("unchecked") // see above - final T readObject = (T) in.readObject(); - return readObject; - - } catch (final ClassNotFoundException ex) { - throw new SerializationException("ClassNotFoundException while reading cloned object data", ex); - } catch (final IOException ex) { - throw new SerializationException("IOException while reading or closing cloned object data", ex); - } - } - - /** - *

- * Deserializes a single {@code Object} from an array of bytes. - *

- * - *

- * If the call site incorrectly types the return value, a - * {@link ClassCastException} is thrown from the call site. Without Generics in - * this declaration, the call site must type cast and can cause the same - * ClassCastException. Note that in both cases, the ClassCastException is in the - * call site, not in this method. - *

- * - * @param the object type to be deserialized - * @param objectData the serialized object, must not be null - * @return the deserialized object - * @throws NullPointerException if {@code objectData} is {@code null} - * @throws SerializationException (runtime) if the serialization fails - */ - public static T deserialize(final byte[] objectData) { - Validate.notNull(objectData, "objectData"); - return deserialize(new EaglerInputStream(objectData)); - } - - /** - *

- * Deserializes an {@code Object} from the specified stream. - *

- * - *

- * The stream will be closed once the object is written. This avoids the need - * for a finally clause, and maybe also exception handling, in the application - * code. - *

- * - *

- * The stream passed in is not buffered internally within this method. This is - * the responsibility of your application if desired. - *

- * - *

- * If the call site incorrectly types the return value, a - * {@link ClassCastException} is thrown from the call site. Without Generics in - * this declaration, the call site must type cast and can cause the same - * ClassCastException. Note that in both cases, the ClassCastException is in the - * call site, not in this method. - *

- * - * @param the object type to be deserialized - * @param inputStream the serialized object input stream, must not be null - * @return the deserialized object - * @throws NullPointerException if {@code inputStream} is {@code null} - * @throws SerializationException (runtime) if the serialization fails - */ - @SuppressWarnings("resource") // inputStream is managed by the caller - public static T deserialize(final InputStream inputStream) { - Validate.notNull(inputStream, "inputStream"); - try (ObjectInputStream in = new ObjectInputStream(inputStream)) { - @SuppressWarnings("unchecked") - final T obj = (T) in.readObject(); - return obj; - } catch (final ClassNotFoundException | IOException ex) { - throw new SerializationException(ex); - } - } - - /** - * Performs a serialization roundtrip. Serializes and deserializes the given - * object, great for testing objects that implement {@link Serializable}. - * - * @param the type of the object involved - * @param obj the object to roundtrip - * @return the serialized and deserialized object - * @since 3.3 - */ - @SuppressWarnings("unchecked") // OK, because we serialized a type `T` - public static T roundtrip(final T obj) { - return (T) deserialize(serialize(obj)); - } - - /** - *

- * Serializes an {@code Object} to a byte array for storage/serialization. - *

- * - * @param obj the object to serialize to bytes - * @return a byte[] with the converted Serializable - * @throws SerializationException (runtime) if the serialization fails - */ - public static byte[] serialize(final Serializable obj) { - final ByteArrayOutputStream baos = new ByteArrayOutputStream(512); - serialize(obj, baos); - return baos.toByteArray(); - } - - /** - *

- * Serializes an {@code Object} to the specified stream. - *

- * - *

- * The stream will be closed once the object is written. This avoids the need - * for a finally clause, and maybe also exception handling, in the application - * code. - *

- * - *

- * The stream passed in is not buffered internally within this method. This is - * the responsibility of your application if desired. - *

- * - * @param obj the object to serialize to bytes, may be null - * @param outputStream the stream to write to, must not be null - * @throws NullPointerException if {@code outputStream} is {@code null} - * @throws SerializationException (runtime) if the serialization fails - */ - @SuppressWarnings("resource") // outputStream is managed by the caller - public static void serialize(final Serializable obj, final OutputStream outputStream) { - Validate.notNull(outputStream, "outputStream"); - try (ObjectOutputStream out = new ObjectOutputStream(outputStream)) { - out.writeObject(obj); - } catch (final IOException ex) { - throw new SerializationException(ex); - } - } - - /** - *

- * SerializationUtils instances should NOT be constructed in standard - * programming. Instead, the class should be used as - * {@code SerializationUtils.clone(object)}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- * - * @since 2.0 - */ - public SerializationUtils() { - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/Streams.java b/sources/main/java/org/apache/commons/lang3/Streams.java deleted file mode 100644 index 47d8d0d8..00000000 --- a/sources/main/java/org/apache/commons/lang3/Streams.java +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collector; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.commons.lang3.Functions.FailableConsumer; -import org.apache.commons.lang3.Functions.FailableFunction; -import org.apache.commons.lang3.Functions.FailablePredicate; - -/** - * Provides utility functions, and classes for working with the - * {@code java.util.stream} package, or more generally, with Java 8 lambdas. - * More specifically, it attempts to address the fact that lambdas are supposed - * not to throw Exceptions, at least not checked Exceptions, AKA instances of - * {@link Exception}. This enforces the use of constructs like - * - *
- * Consumer<java.lang.reflect.Method> consumer = m -> {
- * 	try {
- * 		m.invoke(o, args);
- * 	} catch (Throwable t) {
- * 		throw Functions.rethrow(t);
- * 	}
- * };
- * stream.forEach(consumer);
- * 
- * - * Using a {@link FailableStream}, this can be rewritten as follows: - * - *
- * Streams.failable(stream).forEach((m) -> m.invoke(o, args));
- * 
- * - * Obviously, the second version is much more concise and the spirit of Lambda - * expressions is met better than in the first version. - * - * @see Stream - * @see Functions - * @since 3.10 - * @deprecated Use {@link org.apache.commons.lang3.stream.Streams}. - */ -@Deprecated -public class Streams { - - /** - * A reduced, and simplified version of a {@link Stream} with failable method - * signatures. - * - * @param The streams element type. - * @deprecated Use - * {@link org.apache.commons.lang3.stream.Streams.FailableStream}. - */ - @Deprecated - public static class FailableStream { - - private Stream stream; - private boolean terminated; - - /** - * Constructs a new instance with the given {@code stream}. - * - * @param stream The stream. - */ - public FailableStream(final Stream stream) { - this.stream = stream; - } - - protected void assertNotTerminated() { - if (terminated) { - throw new IllegalStateException("This stream is already terminated."); - } - } - - protected void makeTerminated() { - assertNotTerminated(); - terminated = true; - } - - /** - * Returns a FailableStream consisting of the elements of this stream that match - * the given FailablePredicate. - * - *

- * This is an intermediate operation. - * - * @param predicate a non-interfering, stateless predicate to apply to each - * element to determine if it should be included. - * @return the new stream - */ - public FailableStream filter(final FailablePredicate predicate) { - assertNotTerminated(); - stream = stream.filter(Functions.asPredicate(predicate)); - return this; - } - - /** - * Performs an action for each element of this stream. - * - *

- * This is a terminal operation. - * - *

- * The behavior of this operation is explicitly nondeterministic. For parallel - * stream pipelines, this operation does not guarantee to respect the - * encounter order of the stream, as doing so would sacrifice the benefit of - * parallelism. For any given element, the action may be performed at whatever - * time and in whatever thread the library chooses. If the action accesses - * shared state, it is responsible for providing the required synchronization. - * - * @param action a non-interfering action to perform on the elements - */ - public void forEach(final FailableConsumer action) { - makeTerminated(); - stream().forEach(Functions.asConsumer(action)); - } - - /** - * Performs a mutable reduction operation on the elements of this stream using a - * {@code Collector}. A {@code Collector} encapsulates the functions used as - * arguments to {@link #collect(Supplier, BiConsumer, BiConsumer)}, allowing for - * reuse of collection strategies and composition of collect operations such as - * multiple-level grouping or partitioning. - * - *

- * If the underlying stream is parallel, and the {@code Collector} is - * concurrent, and either the stream is unordered or the collector is unordered, - * then a concurrent reduction will be performed (see {@link Collector} for - * details on concurrent reduction.) - * - *

- * This is a terminal operation. - * - *

- * When executed in parallel, multiple intermediate results may be instantiated, - * populated, and merged so as to maintain isolation of mutable data structures. - * Therefore, even when executed in parallel with non-thread-safe data - * structures (such as {@code ArrayList}), no additional synchronization is - * needed for a parallel reduction. - * - * Note The following will accumulate strings into an ArrayList: - * - *

-		 * {
-		 * 	@code
-		 * 	List asList = stringStream.collect(Collectors.toList());
-		 * }
-		 * 
- * - *

- * The following will classify {@code Person} objects by city: - * - *

-		 * {
-		 * 	@code
-		 * 	Map> peopleByCity = personStream.collect(Collectors.groupingBy(Person::getCity));
-		 * }
-		 * 
- * - *

- * The following will classify {@code Person} objects by state and city, - * cascading two {@code Collector}s together: - * - *

-		 * {
-		 * 	@code
-		 * 	Map>> peopleByStateAndCity = personStream
-		 * 			.collect(Collectors.groupingBy(Person::getState, Collectors.groupingBy(Person::getCity)));
-		 * }
-		 * 
- * - * @param the type of the result - * @param the intermediate accumulation type of the {@code Collector} - * @param collector the {@code Collector} describing the reduction - * @return the result of the reduction - * @see #collect(Supplier, BiConsumer, BiConsumer) - * @see Collectors - */ - public R collect(final Collector collector) { - makeTerminated(); - return stream().collect(collector); - } - - /** - * Performs a mutable reduction operation on the elements of this - * FailableStream. A mutable reduction is one in which the reduced value is a - * mutable result container, such as an {@code ArrayList}, and elements are - * incorporated by updating the state of the result rather than by replacing the - * result. This produces a result equivalent to: - * - *
-		 * {@code
-		 *     R result = supplier.get();
-		 *     for (T element : this stream)
-		 *         accumulator.accept(result, element);
-		 *     return result;
-		 * }
-		 * 
- * - *

- * Like {@link #reduce(Object, BinaryOperator)}, {@code collect} operations can - * be parallelized without requiring additional synchronization. - * - *

- * This is a terminal operation. - * - * Note There are many existing classes in the JDK whose signatures are - * well-suited for use with method references as arguments to {@code collect()}. - * For example, the following will accumulate strings into an {@code ArrayList}: - * - *

-		 * {
-		 * 	@code
-		 * 	List asList = stringStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
-		 * }
-		 * 
- * - *

- * The following will take a stream of strings and concatenates them into a - * single string: - * - *

-		 * {
-		 * 	@code
-		 * 	String concat = stringStream.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
-		 * 			.toString();
-		 * }
-		 * 
- * - * @param type of the result - * @param
Type of the accumulator. - * @param pupplier a function that creates a new result container. For a - * parallel execution, this function may be called multiple - * times and must return a fresh value each time. - * @param accumulator An associative, non-interfering, stateless function for - * incorporating an additional element into a result - * @param combiner An associative, non-interfering, stateless function for - * combining two values, which must be compatible with the - * accumulator function - * @return The result of the reduction - */ - public R collect(final Supplier pupplier, final BiConsumer accumulator, - final BiConsumer combiner) { - makeTerminated(); - return stream().collect(pupplier, accumulator, combiner); - } - - /** - * Performs a reduction on the elements of this stream, using the provided - * identity value and an associative accumulation function, and returns the - * reduced value. This is equivalent to: - * - *
-		 * {@code
-		 *     T result = identity;
-		 *     for (T element : this stream)
-		 *         result = accumulator.apply(result, element)
-		 *     return result;
-		 * }
-		 * 
- * - * but is not constrained to execute sequentially. - * - *

- * The {@code identity} value must be an identity for the accumulator function. - * This means that for all {@code t}, {@code accumulator.apply(identity, t)} is - * equal to {@code t}. The {@code accumulator} function must be an associative - * function. - * - *

- * This is a terminal operation. - * - * Note Sum, min, max, average, and string concatenation are all special cases - * of reduction. Summing a stream of numbers can be expressed as: - * - *

-		 * {
-		 * 	@code
-		 * 	Integer sum = integers.reduce(0, (a, b) -> a + b);
-		 * }
-		 * 
- * - * or: - * - *
-		 * {
-		 * 	@code
-		 * 	Integer sum = integers.reduce(0, Integer::sum);
-		 * }
-		 * 
- * - *

- * While this may seem a more roundabout way to perform an aggregation compared - * to simply mutating a running total in a loop, reduction operations - * parallelize more gracefully, without needing additional synchronization and - * with greatly reduced risk of data races. - * - * @param identity the identity value for the accumulating function - * @param accumulator an associative, non-interfering, stateless function for - * combining two values - * @return the result of the reduction - */ - public O reduce(final O identity, final BinaryOperator accumulator) { - makeTerminated(); - return stream().reduce(identity, accumulator); - } - - /** - * Returns a stream consisting of the results of applying the given function to - * the elements of this stream. - * - *

- * This is an intermediate operation. - * - * @param The element type of the new stream - * @param mapper A non-interfering, stateless function to apply to each element - * @return the new stream - */ - public FailableStream map(final FailableFunction mapper) { - assertNotTerminated(); - return new FailableStream<>(stream.map(Functions.asFunction(mapper))); - } - - /** - * Converts the FailableStream into an equivalent stream. - * - * @return A stream, which will return the same elements, which this - * FailableStream would return. - */ - public Stream stream() { - return stream; - } - - /** - * Returns whether all elements of this stream match the provided predicate. May - * not evaluate the predicate on all elements if not necessary for determining - * the result. If the stream is empty then {@code true} is returned and the - * predicate is not evaluated. - * - *

- * This is a short-circuiting terminal operation. - * - * Note This method evaluates the universal quantification of the - * predicate over the elements of the stream (for all x P(x)). If the stream is - * empty, the quantification is said to be vacuously satisfied and is - * always {@code true} (regardless of P(x)). - * - * @param predicate A non-interfering, stateless predicate to apply to elements - * of this stream - * @return {@code true} If either all elements of the stream match the provided - * predicate or the stream is empty, otherwise {@code false}. - */ - public boolean allMatch(final FailablePredicate predicate) { - assertNotTerminated(); - return stream().allMatch(Functions.asPredicate(predicate)); - } - - /** - * Returns whether any elements of this stream match the provided predicate. May - * not evaluate the predicate on all elements if not necessary for determining - * the result. If the stream is empty then {@code false} is returned and the - * predicate is not evaluated. - * - *

- * This is a short-circuiting terminal operation. - * - * Note This method evaluates the existential quantification of the - * predicate over the elements of the stream (for some x P(x)). - * - * @param predicate A non-interfering, stateless predicate to apply to elements - * of this stream - * @return {@code true} if any elements of the stream match the provided - * predicate, otherwise {@code false} - */ - public boolean anyMatch(final FailablePredicate predicate) { - assertNotTerminated(); - return stream().anyMatch(Functions.asPredicate(predicate)); - } - } - - /** - * Converts the given {@link Stream stream} into a {@link FailableStream}. This - * is basically a simplified, reduced version of the {@link Stream} class, with - * the same underlying element stream, except that failable objects, like - * {@link FailablePredicate}, {@link FailableFunction}, or - * {@link FailableConsumer} may be applied, instead of {@link Predicate}, - * {@link Function}, or {@link Consumer}. The idea is to rewrite a code snippet - * like this: - * - *

-	 * final List<O> list;
-	 * final Method m;
-	 * final Function<O, String> mapper = (o) -> {
-	 * 	try {
-	 * 		return (String) m.invoke(o);
-	 * 	} catch (Throwable t) {
-	 * 		throw Functions.rethrow(t);
-	 * 	}
-	 * };
-	 * final List<String> strList = list.stream().map(mapper).collect(Collectors.toList());
-	 * 
- * - * as follows: - * - *
-	 * final List<O> list;
-	 * final Method m;
-	 * final List<String> strList = Functions.stream(list.stream()).map((o) -> (String) m.invoke(o))
-	 * 		.collect(Collectors.toList());
-	 * 
- * - * While the second version may not be quite as efficient (because it - * depends on the creation of additional, intermediate objects, of type - * FailableStream), it is much more concise, and readable, and meets the spirit - * of Lambdas better than the first version. - * - * @param The streams element type. - * @param stream The stream, which is being converted. - * @return The {@link FailableStream}, which has been created by converting the - * stream. - */ - public static FailableStream stream(final Stream stream) { - return new FailableStream<>(stream); - } - - /** - * Converts the given {@link Collection} into a {@link FailableStream}. This is - * basically a simplified, reduced version of the {@link Stream} class, with the - * same underlying element stream, except that failable objects, like - * {@link FailablePredicate}, {@link FailableFunction}, or - * {@link FailableConsumer} may be applied, instead of {@link Predicate}, - * {@link Function}, or {@link Consumer}. The idea is to rewrite a code snippet - * like this: - * - *
-	 * final List<O> list;
-	 * final Method m;
-	 * final Function<O, String> mapper = (o) -> {
-	 * 	try {
-	 * 		return (String) m.invoke(o);
-	 * 	} catch (Throwable t) {
-	 * 		throw Functions.rethrow(t);
-	 * 	}
-	 * };
-	 * final List<String> strList = list.stream().map(mapper).collect(Collectors.toList());
-	 * 
- * - * as follows: - * - *
-	 * final List<O> list;
-	 * final Method m;
-	 * final List<String> strList = Functions.stream(list.stream()).map((o) -> (String) m.invoke(o))
-	 * 		.collect(Collectors.toList());
-	 * 
- * - * While the second version may not be quite as efficient (because it - * depends on the creation of additional, intermediate objects, of type - * FailableStream), it is much more concise, and readable, and meets the spirit - * of Lambdas better than the first version. - * - * @param The streams element type. - * @param stream The stream, which is being converted. - * @return The {@link FailableStream}, which has been created by converting the - * stream. - */ - public static FailableStream stream(final Collection stream) { - return stream(stream.stream()); - } - - /** - * A Collector type for arrays. - * - * @param The array type. - * @deprecated Use - * {@link org.apache.commons.lang3.stream.Streams.ArrayCollector}. - */ - @Deprecated - public static class ArrayCollector implements Collector, O[]> { - private static final Set characteristics = Collections.emptySet(); - private final Class elementType; - - /** - * Constructs a new instance for the given element type. - * - * @param elementType The element type. - */ - public ArrayCollector(final Class elementType) { - this.elementType = elementType; - } - - @Override - public Supplier> supplier() { - return ArrayList::new; - } - - @Override - public BiConsumer, O> accumulator() { - return List::add; - } - - @Override - public BinaryOperator> combiner() { - return (left, right) -> { - left.addAll(right); - return left; - }; - } - - @Override - public Function, O[]> finisher() { - return list -> { - @SuppressWarnings("unchecked") - final O[] array = (O[]) Array.newInstance(elementType, list.size()); - return list.toArray(array); - }; - } - - @Override - public Set characteristics() { - return characteristics; - } - } - - /** - * Returns a {@code Collector} that accumulates the input elements into a new - * array. - * - * @param pElementType Type of an element in the array. - * @param the type of the input elements - * @return a {@code Collector} which collects all the input elements into an - * array, in encounter order - */ - public static Collector toArray(final Class pElementType) { - return new ArrayCollector<>(pElementType); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/StringEscapeUtils.java b/sources/main/java/org/apache/commons/lang3/StringEscapeUtils.java deleted file mode 100644 index 45f850a1..00000000 --- a/sources/main/java/org/apache/commons/lang3/StringEscapeUtils.java +++ /dev/null @@ -1,849 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.io.IOException; -import java.io.Writer; - -import org.apache.commons.lang3.text.translate.AggregateTranslator; -import org.apache.commons.lang3.text.translate.CharSequenceTranslator; -import org.apache.commons.lang3.text.translate.EntityArrays; -import org.apache.commons.lang3.text.translate.JavaUnicodeEscaper; -import org.apache.commons.lang3.text.translate.LookupTranslator; -import org.apache.commons.lang3.text.translate.NumericEntityEscaper; -import org.apache.commons.lang3.text.translate.NumericEntityUnescaper; -import org.apache.commons.lang3.text.translate.OctalUnescaper; -import org.apache.commons.lang3.text.translate.UnicodeUnescaper; -import org.apache.commons.lang3.text.translate.UnicodeUnpairedSurrogateRemover; - -/** - *

- * Escapes and unescapes {@code String}s for Java, Java Script, HTML and XML. - *

- * - *

- * #ThreadSafe# - *

- * - * @since 2.0 - * @version $Id: StringEscapeUtils.java 1583482 2014-03-31 22:54:57Z niallp $ - */ -public class StringEscapeUtils { - - /* ESCAPE TRANSLATORS */ - - /** - * Translator object for escaping Java. - * - * While {@link #escapeJava(String)} is the expected method of use, this object - * allows the Java escaping functionality to be used as the foundation for a - * custom translator. - * - * @since 3.0 - */ - public static final CharSequenceTranslator ESCAPE_JAVA = new LookupTranslator( - new String[][] { { "\"", "\\\"" }, { "\\", "\\\\" }, }) - .with(new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE())) - .with(JavaUnicodeEscaper.outsideOf(32, 0x7f)); - - /** - * Translator object for escaping EcmaScript/JavaScript. - * - * While {@link #escapeEcmaScript(String)} is the expected method of use, this - * object allows the EcmaScript escaping functionality to be used as the - * foundation for a custom translator. - * - * @since 3.0 - */ - public static final CharSequenceTranslator ESCAPE_ECMASCRIPT = new AggregateTranslator( - new LookupTranslator(new String[][] { { "'", "\\'" }, { "\"", "\\\"" }, { "\\", "\\\\" }, { "/", "\\/" } }), - new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE()), JavaUnicodeEscaper.outsideOf(32, 0x7f)); - - /** - * Translator object for escaping Json. - * - * While {@link #escapeJson(String)} is the expected method of use, this object - * allows the Json escaping functionality to be used as the foundation for a - * custom translator. - * - * @since 3.2 - */ - public static final CharSequenceTranslator ESCAPE_JSON = new AggregateTranslator( - new LookupTranslator(new String[][] { { "\"", "\\\"" }, { "\\", "\\\\" }, { "/", "\\/" } }), - new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE()), JavaUnicodeEscaper.outsideOf(32, 0x7f)); - - /** - * Translator object for escaping XML. - * - * While {@link #escapeXml(String)} is the expected method of use, this object - * allows the XML escaping functionality to be used as the foundation for a - * custom translator. - * - * @since 3.0 - * @deprecated use {@link #ESCAPE_XML10} or {@link #ESCAPE_XML11} instead. - */ - @Deprecated - public static final CharSequenceTranslator ESCAPE_XML = new AggregateTranslator( - new LookupTranslator(EntityArrays.BASIC_ESCAPE()), new LookupTranslator(EntityArrays.APOS_ESCAPE())); - - /** - * Translator object for escaping XML 1.0. - * - * While {@link #escapeXml10(String)} is the expected method of use, this object - * allows the XML escaping functionality to be used as the foundation for a - * custom translator. - * - * @since 3.3 - */ - public static final CharSequenceTranslator ESCAPE_XML10 = new AggregateTranslator( - new LookupTranslator(EntityArrays.BASIC_ESCAPE()), new LookupTranslator(EntityArrays.APOS_ESCAPE()), - new LookupTranslator(new String[][] { { "\u0000", "" }, { "\u0001", "" }, { "\u0002", "" }, - { "\u0003", "" }, { "\u0004", "" }, { "\u0005", "" }, { "\u0006", "" }, { "\u0007", "" }, - { "\u0008", "" }, { "\u000b", "" }, { "\u000c", "" }, { "\u000e", "" }, { "\u000f", "" }, - { "\u0010", "" }, { "\u0011", "" }, { "\u0012", "" }, { "\u0013", "" }, { "\u0014", "" }, - { "\u0015", "" }, { "\u0016", "" }, { "\u0017", "" }, { "\u0018", "" }, { "\u0019", "" }, - { "\u001a", "" }, { "\u001b", "" }, { "\u001c", "" }, { "\u001d", "" }, { "\u001e", "" }, - { "\u001f", "" }, { "\ufffe", "" }, { "\uffff", "" } }), - NumericEntityEscaper.between(0x7f, 0x84), NumericEntityEscaper.between(0x86, 0x9f), - new UnicodeUnpairedSurrogateRemover()); - - /** - * Translator object for escaping XML 1.1. - * - * While {@link #escapeXml11(String)} is the expected method of use, this object - * allows the XML escaping functionality to be used as the foundation for a - * custom translator. - * - * @since 3.3 - */ - public static final CharSequenceTranslator ESCAPE_XML11 = new AggregateTranslator( - new LookupTranslator(EntityArrays.BASIC_ESCAPE()), new LookupTranslator(EntityArrays.APOS_ESCAPE()), - new LookupTranslator(new String[][] { { "\u0000", "" }, { "\u000b", " " }, { "\u000c", " " }, - { "\ufffe", "" }, { "\uffff", "" } }), - NumericEntityEscaper.between(0x1, 0x8), NumericEntityEscaper.between(0xe, 0x1f), - NumericEntityEscaper.between(0x7f, 0x84), NumericEntityEscaper.between(0x86, 0x9f), - new UnicodeUnpairedSurrogateRemover()); - - /** - * Translator object for escaping HTML version 3.0. - * - * While {@link #escapeHtml3(String)} is the expected method of use, this object - * allows the HTML escaping functionality to be used as the foundation for a - * custom translator. - * - * @since 3.0 - */ - public static final CharSequenceTranslator ESCAPE_HTML3 = new AggregateTranslator( - new LookupTranslator(EntityArrays.BASIC_ESCAPE()), new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE())); - - /** - * Translator object for escaping HTML version 4.0. - * - * While {@link #escapeHtml4(String)} is the expected method of use, this object - * allows the HTML escaping functionality to be used as the foundation for a - * custom translator. - * - * @since 3.0 - */ - public static final CharSequenceTranslator ESCAPE_HTML4 = new AggregateTranslator( - new LookupTranslator(EntityArrays.BASIC_ESCAPE()), new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE()), - new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE())); - - /** - * Translator object for escaping individual Comma Separated Values. - * - * While {@link #escapeCsv(String)} is the expected method of use, this object - * allows the CSV escaping functionality to be used as the foundation for a - * custom translator. - * - * @since 3.0 - */ - public static final CharSequenceTranslator ESCAPE_CSV = new CsvEscaper(); - - // TODO: Create a parent class - 'SinglePassTranslator' ? - // It would handle the index checking + length returning, - // and could also have an optimization check method. - static class CsvEscaper extends CharSequenceTranslator { - - private static final char CSV_DELIMITER = ','; - private static final char CSV_QUOTE = '"'; - private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE); - private static final char[] CSV_SEARCH_CHARS = new char[] { CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, - CharUtils.LF }; - - @Override - public int translate(final CharSequence input, final int index, final Writer out) throws IOException { - - if (index != 0) { - throw new IllegalStateException("CsvEscaper should never reach the [1] index"); - } - - if (StringUtils.containsNone(input.toString(), CSV_SEARCH_CHARS)) { - out.write(input.toString()); - } else { - out.write(CSV_QUOTE); - out.write(StringUtils.replace(input.toString(), CSV_QUOTE_STR, CSV_QUOTE_STR + CSV_QUOTE_STR)); - out.write(CSV_QUOTE); - } - return Character.codePointCount(input, 0, input.length()); - } - } - - /* UNESCAPE TRANSLATORS */ - - /** - * Translator object for unescaping escaped Java. - * - * While {@link #unescapeJava(String)} is the expected method of use, this - * object allows the Java unescaping functionality to be used as the foundation - * for a custom translator. - * - * @since 3.0 - */ - // TODO: throw "illegal character: \92" as an Exception if a \ on the end of the - // Java (as per the compiler)? - public static final CharSequenceTranslator UNESCAPE_JAVA = new AggregateTranslator(new OctalUnescaper(), // .between('\1', - // '\377'), - new UnicodeUnescaper(), new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_UNESCAPE()), - new LookupTranslator(new String[][] { { "\\\\", "\\" }, { "\\\"", "\"" }, { "\\'", "'" }, { "\\", "" } })); - - /** - * Translator object for unescaping escaped EcmaScript. - * - * While {@link #unescapeEcmaScript(String)} is the expected method of use, this - * object allows the EcmaScript unescaping functionality to be used as the - * foundation for a custom translator. - * - * @since 3.0 - */ - public static final CharSequenceTranslator UNESCAPE_ECMASCRIPT = UNESCAPE_JAVA; - - /** - * Translator object for unescaping escaped Json. - * - * While {@link #unescapeJson(String)} is the expected method of use, this - * object allows the Json unescaping functionality to be used as the foundation - * for a custom translator. - * - * @since 3.2 - */ - public static final CharSequenceTranslator UNESCAPE_JSON = UNESCAPE_JAVA; - - /** - * Translator object for unescaping escaped HTML 3.0. - * - * While {@link #unescapeHtml3(String)} is the expected method of use, this - * object allows the HTML unescaping functionality to be used as the foundation - * for a custom translator. - * - * @since 3.0 - */ - public static final CharSequenceTranslator UNESCAPE_HTML3 = new AggregateTranslator( - new LookupTranslator(EntityArrays.BASIC_UNESCAPE()), - new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE()), new NumericEntityUnescaper()); - - /** - * Translator object for unescaping escaped HTML 4.0. - * - * While {@link #unescapeHtml4(String)} is the expected method of use, this - * object allows the HTML unescaping functionality to be used as the foundation - * for a custom translator. - * - * @since 3.0 - */ - public static final CharSequenceTranslator UNESCAPE_HTML4 = new AggregateTranslator( - new LookupTranslator(EntityArrays.BASIC_UNESCAPE()), - new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE()), - new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE()), new NumericEntityUnescaper()); - - /** - * Translator object for unescaping escaped XML. - * - * While {@link #unescapeXml(String)} is the expected method of use, this object - * allows the XML unescaping functionality to be used as the foundation for a - * custom translator. - * - * @since 3.0 - */ - public static final CharSequenceTranslator UNESCAPE_XML = new AggregateTranslator( - new LookupTranslator(EntityArrays.BASIC_UNESCAPE()), new LookupTranslator(EntityArrays.APOS_UNESCAPE()), - new NumericEntityUnescaper()); - - /** - * Translator object for unescaping escaped Comma Separated Value entries. - * - * While {@link #unescapeCsv(String)} is the expected method of use, this object - * allows the CSV unescaping functionality to be used as the foundation for a - * custom translator. - * - * @since 3.0 - */ - public static final CharSequenceTranslator UNESCAPE_CSV = new CsvUnescaper(); - - static class CsvUnescaper extends CharSequenceTranslator { - - private static final char CSV_DELIMITER = ','; - private static final char CSV_QUOTE = '"'; - private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE); - private static final char[] CSV_SEARCH_CHARS = new char[] { CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, - CharUtils.LF }; - - @Override - public int translate(final CharSequence input, final int index, final Writer out) throws IOException { - - if (index != 0) { - throw new IllegalStateException("CsvUnescaper should never reach the [1] index"); - } - - if (input.charAt(0) != CSV_QUOTE || input.charAt(input.length() - 1) != CSV_QUOTE) { - out.write(input.toString()); - return Character.codePointCount(input, 0, input.length()); - } - - // strip quotes - final String quoteless = input.subSequence(1, input.length() - 1).toString(); - - if (StringUtils.containsAny(quoteless, CSV_SEARCH_CHARS)) { - // deal with escaped quotes; ie) "" - out.write(StringUtils.replace(quoteless, CSV_QUOTE_STR + CSV_QUOTE_STR, CSV_QUOTE_STR)); - } else { - out.write(input.toString()); - } - return Character.codePointCount(input, 0, input.length()); - } - } - - /* Helper functions */ - - /** - *

- * {@code StringEscapeUtils} instances should NOT be constructed in standard - * programming. - *

- * - *

- * Instead, the class should be used as: - *

- * - *
-	 * StringEscapeUtils.escapeJava("foo");
-	 * 
- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public StringEscapeUtils() { - super(); - } - - // Java and JavaScript - // -------------------------------------------------------------------------- - /** - *

- * Escapes the characters in a {@code String} using Java String rules. - *

- * - *

- * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) - *

- * - *

- * So a tab becomes the characters {@code '\\'} and {@code 't'}. - *

- * - *

- * The only difference between Java strings and JavaScript strings is that in - * JavaScript, a single quote and forward-slash (/) are escaped. - *

- * - *

- * Example: - *

- * - *
-	 * input string: He didn't say, "Stop!"
-	 * output string: He didn't say, \"Stop!\"
-	 * 
- * - * @param input String to escape values in, may be null - * @return String with escaped values, {@code null} if null string input - */ - public static final String escapeJava(final String input) { - return ESCAPE_JAVA.translate(input); - } - - /** - *

- * Escapes the characters in a {@code String} using EcmaScript String rules. - *

- *

- * Escapes any values it finds into their EcmaScript String form. Deals - * correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) - *

- * - *

- * So a tab becomes the characters {@code '\\'} and {@code 't'}. - *

- * - *

- * The only difference between Java strings and EcmaScript strings is that in - * EcmaScript, a single quote and forward-slash (/) are escaped. - *

- * - *

- * Note that EcmaScript is best known by the JavaScript and ActionScript - * dialects. - *

- * - *

- * Example: - *

- * - *
-	 * input string: He didn't say, "Stop!"
-	 * output string: He didn\'t say, \"Stop!\"
-	 * 
- * - * @param input String to escape values in, may be null - * @return String with escaped values, {@code null} if null string input - * - * @since 3.0 - */ - public static final String escapeEcmaScript(final String input) { - return ESCAPE_ECMASCRIPT.translate(input); - } - - /** - *

- * Escapes the characters in a {@code String} using Json String rules. - *

- *

- * Escapes any values it finds into their Json String form. Deals correctly with - * quotes and control-chars (tab, backslash, cr, ff, etc.) - *

- * - *

- * So a tab becomes the characters {@code '\\'} and {@code 't'}. - *

- * - *

- * The only difference between Java strings and Json strings is that in Json, - * forward-slash (/) is escaped. - *

- * - *

- * See http://www.ietf.org/rfc/rfc4627.txt for further details. - *

- * - *

- * Example: - *

- * - *
-	 * input string: He didn't say, "Stop!"
-	 * output string: He didn't say, \"Stop!\"
-	 * 
- * - * @param input String to escape values in, may be null - * @return String with escaped values, {@code null} if null string input - * - * @since 3.2 - */ - public static final String escapeJson(final String input) { - return ESCAPE_JSON.translate(input); - } - - /** - *

- * Unescapes any Java literals found in the {@code String}. For example, it will - * turn a sequence of {@code '\'} and {@code 'n'} into a newline character, - * unless the {@code '\'} is preceded by another {@code '\'}. - *

- * - * @param input the {@code String} to unescape, may be null - * @return a new unescaped {@code String}, {@code null} if null string input - */ - public static final String unescapeJava(final String input) { - return UNESCAPE_JAVA.translate(input); - } - - /** - *

- * Unescapes any EcmaScript literals found in the {@code String}. - *

- * - *

- * For example, it will turn a sequence of {@code '\'} and {@code 'n'} into a - * newline character, unless the {@code '\'} is preceded by another {@code '\'}. - *

- * - * @see #unescapeJava(String) - * @param input the {@code String} to unescape, may be null - * @return A new unescaped {@code String}, {@code null} if null string input - * - * @since 3.0 - */ - public static final String unescapeEcmaScript(final String input) { - return UNESCAPE_ECMASCRIPT.translate(input); - } - - /** - *

- * Unescapes any Json literals found in the {@code String}. - *

- * - *

- * For example, it will turn a sequence of {@code '\'} and {@code 'n'} into a - * newline character, unless the {@code '\'} is preceded by another {@code '\'}. - *

- * - * @see #unescapeJava(String) - * @param input the {@code String} to unescape, may be null - * @return A new unescaped {@code String}, {@code null} if null string input - * - * @since 3.2 - */ - public static final String unescapeJson(final String input) { - return UNESCAPE_JSON.translate(input); - } - - // HTML and XML - // -------------------------------------------------------------------------- - /** - *

- * Escapes the characters in a {@code String} using HTML entities. - *

- * - *

- * For example: - *

- *

- * "bread" & "butter" - *

- * becomes: - *

- * &quot;bread&quot; &amp; &quot;butter&quot;. - *

- * - *

- * Supports all known HTML 4.0 entities, including funky accents. Note that the - * commonly used apostrophe escape character (&apos;) is not a legal entity - * and so is not supported). - *

- * - * @param input the {@code String} to escape, may be null - * @return a new escaped {@code String}, {@code null} if null string input - * - * @see
ISO - * Entities - * @see HTML 3.2 Character - * Entities for ISO Latin-1 - * @see HTML 4.0 - * Character entity references - * @see HTML 4.01 - * Character References - * @see HTML - * 4.01 Code positions - * - * @since 3.0 - */ - public static final String escapeHtml4(final String input) { - return ESCAPE_HTML4.translate(input); - } - - /** - *

- * Escapes the characters in a {@code String} using HTML entities. - *

- *

- * Supports only the HTML 3.0 entities. - *

- * - * @param input the {@code String} to escape, may be null - * @return a new escaped {@code String}, {@code null} if null string input - * - * @since 3.0 - */ - public static final String escapeHtml3(final String input) { - return ESCAPE_HTML3.translate(input); - } - - // ----------------------------------------------------------------------- - /** - *

- * Unescapes a string containing entity escapes to a string containing the - * actual Unicode characters corresponding to the escapes. Supports HTML 4.0 - * entities. - *

- * - *

- * For example, the string "&lt;Fran&ccedil;ais&gt;" will become - * "<Français>" - *

- * - *

- * If an entity is unrecognized, it is left alone, and inserted verbatim into - * the result string. e.g. "&gt;&zzzz;x" will become ">&zzzz;x". - *

- * - * @param input the {@code String} to unescape, may be null - * @return a new unescaped {@code String}, {@code null} if null string input - * - * @since 3.0 - */ - public static final String unescapeHtml4(final String input) { - return UNESCAPE_HTML4.translate(input); - } - - /** - *

- * Unescapes a string containing entity escapes to a string containing the - * actual Unicode characters corresponding to the escapes. Supports only HTML - * 3.0 entities. - *

- * - * @param input the {@code String} to unescape, may be null - * @return a new unescaped {@code String}, {@code null} if null string input - * - * @since 3.0 - */ - public static final String unescapeHtml3(final String input) { - return UNESCAPE_HTML3.translate(input); - } - - // ----------------------------------------------------------------------- - /** - *

- * Escapes the characters in a {@code String} using XML entities. - *

- * - *

- * For example: "bread" & "butter" => - * &quot;bread&quot; &amp; &quot;butter&quot;. - *

- * - *

- * Supports only the five basic XML entities (gt, lt, quot, amp, apos). Does not - * support DTDs or external entities. - *

- * - *

- * Note that Unicode characters greater than 0x7f are as of 3.0, no longer - * escaped. If you still wish this functionality, you can achieve it via the - * following: - * {@code StringEscapeUtils.ESCAPE_XML.with( NumericEntityEscaper.between(0x7f, Integer.MAX_VALUE) );} - *

- * - * @param input the {@code String} to escape, may be null - * @return a new escaped {@code String}, {@code null} if null string input - * @see #unescapeXml(java.lang.String) - * @deprecated use {@link #escapeXml10(java.lang.String)} or - * {@link #escapeXml11(java.lang.String)} instead. - */ - @Deprecated - public static final String escapeXml(final String input) { - return ESCAPE_XML.translate(input); - } - - /** - *

- * Escapes the characters in a {@code String} using XML entities. - *

- * - *

- * For example: "bread" & "butter" => - * &quot;bread&quot; &amp; &quot;butter&quot;. - *

- * - *

- * Note that XML 1.0 is a text-only format: it cannot represent control - * characters or unpaired Unicode surrogate codepoints, even after escaping. - * {@code escapeXml10} will remove characters that do not fit in the following - * ranges: - *

- * - *

- * {@code #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]} - *

- * - *

- * Though not strictly necessary, {@code escapeXml10} will escape characters in - * the following ranges: - *

- * - *

- * {@code [#x7F-#x84] | [#x86-#x9F]} - *

- * - *

- * The returned string can be inserted into a valid XML 1.0 or XML 1.1 document. - * If you want to allow more non-text characters in an XML 1.1 document, use - * {@link #escapeXml11(String)}. - *

- * - * @param input the {@code String} to escape, may be null - * @return a new escaped {@code String}, {@code null} if null string input - * @see #unescapeXml(java.lang.String) - * @since 3.3 - */ - public static String escapeXml10(final String input) { - return ESCAPE_XML10.translate(input); - } - - /** - *

- * Escapes the characters in a {@code String} using XML entities. - *

- * - *

- * For example: "bread" & "butter" => - * &quot;bread&quot; &amp; &quot;butter&quot;. - *

- * - *

- * XML 1.1 can represent certain control characters, but it cannot represent the - * null byte or unpaired Unicode surrogate codepoints, even after escaping. - * {@code escapeXml11} will remove characters that do not fit in the following - * ranges: - *

- * - *

- * {@code [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]} - *

- * - *

- * {@code escapeXml11} will escape characters in the following ranges: - *

- * - *

- * {@code [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]} - *

- * - *

- * The returned string can be inserted into a valid XML 1.1 document. Do not use - * it for XML 1.0 documents. - *

- * - * @param input the {@code String} to escape, may be null - * @return a new escaped {@code String}, {@code null} if null string input - * @see #unescapeXml(java.lang.String) - * @since 3.3 - */ - public static String escapeXml11(final String input) { - return ESCAPE_XML11.translate(input); - } - - // ----------------------------------------------------------------------- - /** - *

- * Unescapes a string containing XML entity escapes to a string containing the - * actual Unicode characters corresponding to the escapes. - *

- * - *

- * Supports only the five basic XML entities (gt, lt, quot, amp, apos). Does not - * support DTDs or external entities. - *

- * - *

- * Note that numerical \\u Unicode codes are unescaped to their respective - * Unicode characters. This may change in future releases. - *

- * - * @param input the {@code String} to unescape, may be null - * @return a new unescaped {@code String}, {@code null} if null string input - * @see #escapeXml(String) - * @see #escapeXml10(String) - * @see #escapeXml11(String) - */ - public static final String unescapeXml(final String input) { - return UNESCAPE_XML.translate(input); - } - - // ----------------------------------------------------------------------- - - /** - *

- * Returns a {@code String} value for a CSV column enclosed in double quotes, if - * required. - *

- * - *

- * If the value contains a comma, newline or double quote, then the String value - * is returned enclosed in double quotes. - *

- * - *

- * Any double quote characters in the value are escaped with another double - * quote. - *

- * - *

- * If the value does not contain a comma, newline or double quote, then the - * String value is returned unchanged. - *

- * - * see - * Wikipedia - * and RFC 4180. - * - * @param input the input CSV column String, may be null - * @return the input String, enclosed in double quotes if the value contains a - * comma, newline or double quote, {@code null} if null string input - * @since 2.4 - */ - public static final String escapeCsv(final String input) { - return ESCAPE_CSV.translate(input); - } - - /** - *

- * Returns a {@code String} value for an unescaped CSV column. - *

- * - *

- * If the value is enclosed in double quotes, and contains a comma, newline or - * double quote, then quotes are removed. - *

- * - *

- * Any double quote escaped characters (a pair of double quotes) are unescaped - * to just one double quote. - *

- * - *

- * If the value is not enclosed in double quotes, or is and does not contain a - * comma, newline or double quote, then the String value is returned unchanged. - *

- * - * see - * Wikipedia - * and RFC 4180. - * - * @param input the input CSV column String, may be null - * @return the input String, with enclosing double quotes removed and embedded - * double quotes unescaped, {@code null} if null string input - * @since 2.4 - */ - public static final String unescapeCsv(final String input) { - return UNESCAPE_CSV.translate(input); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/StringUtils.java b/sources/main/java/org/apache/commons/lang3/StringUtils.java deleted file mode 100644 index 5acabc92..00000000 --- a/sources/main/java/org/apache/commons/lang3/StringUtils.java +++ /dev/null @@ -1,10513 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.text.Normalizer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Objects; -import java.util.Set; -import java.util.StringJoiner; -import java.util.function.Supplier; -import java.util.regex.Pattern; - -import net.lax1dude.eaglercraft.v1_8.HString; - -import org.apache.commons.lang3.function.ToBooleanBiFunction; - -/** - *

- * Operations on {@link java.lang.String} that are {@code null} safe. - *

- * - *
    - *
  • IsEmpty/IsBlank - checks if a String contains text
  • - *
  • Trim/Strip - removes leading and trailing whitespace
  • - *
  • Equals/Compare - compares two strings in a null-safe manner
  • - *
  • startsWith - check if a String starts with a prefix in a null-safe - * manner
  • - *
  • endsWith - check if a String ends with a suffix in a null-safe - * manner
  • - *
  • IndexOf/LastIndexOf/Contains - null-safe index-of checks - *
  • IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut - - * index-of any of a set of Strings
  • - *
  • ContainsOnly/ContainsNone/ContainsAny - checks if String contains - * only/none/any of these characters
  • - *
  • Substring/Left/Right/Mid - null-safe substring extractions
  • - *
  • SubstringBefore/SubstringAfter/SubstringBetween - substring - * extraction relative to other strings
  • - *
  • Split/Join - splits a String into an array of substrings and vice - * versa
  • - *
  • Remove/Delete - removes part of a String
  • - *
  • Replace/Overlay - Searches a String and replaces one String with - * another
  • - *
  • Chomp/Chop - removes the last part of a String
  • - *
  • AppendIfMissing - appends a suffix to the end of the String if not - * present
  • - *
  • PrependIfMissing - prepends a prefix to the start of the String if - * not present
  • - *
  • LeftPad/RightPad/Center/Repeat - pads a String
  • - *
  • UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize - changes the - * case of a String
  • - *
  • CountMatches - counts the number of occurrences of one String in - * another
  • - *
  • IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable - checks the - * characters in a String
  • - *
  • DefaultString - protects against a null input String
  • - *
  • Rotate - rotate (circular shift) a String
  • - *
  • Reverse/ReverseDelimited - reverses a String
  • - *
  • Abbreviate - abbreviates a string using ellipses or another given - * String
  • - *
  • Difference - compares Strings and reports on their - * differences
  • - *
  • LevenshteinDistance - the number of changes needed to change one - * String into another
  • - *
- * - *

- * The {@code StringUtils} class defines certain words related to String - * handling. - *

- * - *
    - *
  • null - {@code null}
  • - *
  • empty - a zero-length string ({@code ""})
  • - *
  • space - the space character ({@code ' '}, char 32)
  • - *
  • whitespace - the characters defined by - * {@link Character#isWhitespace(char)}
  • - *
  • trim - the characters <= 32 as in {@link String#trim()}
  • - *
- * - *

- * {@code StringUtils} handles {@code null} input Strings quietly. That is to - * say that a {@code null} input will return {@code null}. Where a - * {@code boolean} or {@code int} is being returned details vary by method. - *

- * - *

- * A side effect of the {@code null} handling is that a - * {@code NullPointerException} should be considered a bug in - * {@code StringUtils}. - *

- * - *

- * Methods in this class include sample code in their Javadoc comments to - * explain their operation. The symbol {@code *} is used to indicate any input - * including {@code null}. - *

- * - *

- * #ThreadSafe# - *

- * - * @see java.lang.String - * @since 1.0 - */ -//@Immutable -public class StringUtils { - - private static final int STRING_BUILDER_SIZE = 256; - - // Performance testing notes (JDK 1.4, Jul03, scolebourne) - // Whitespace: - // Character.isWhitespace() is faster than WHITESPACE.indexOf() - // where WHITESPACE is a string of all whitespace characters - // - // Character access: - // String.charAt(n) versus toCharArray(), then array[n] - // String.charAt(n) is about 15% worse for a 10K string - // They are about equal for a length 50 string - // String.charAt(n) is about 4 times better for a length 3 string - // String.charAt(n) is best bet overall - // - // Append: - // String.concat about twice as fast as StringBuffer.append - // (not sure who tested this) - - /** - * A String for a space character. - * - * @since 3.2 - */ - public static final String SPACE = " "; - - /** - * The empty String {@code ""}. - * - * @since 2.0 - */ - public static final String EMPTY = ""; - - /** - * A String for linefeed LF ("\n"). - * - * @see JLF: - * Escape Sequences for Character and String Literals - * @since 3.2 - */ - public static final String LF = "\n"; - - /** - * A String for carriage return CR ("\r"). - * - * @see JLF: - * Escape Sequences for Character and String Literals - * @since 3.2 - */ - public static final String CR = "\r"; - - /** - * Represents a failed index search. - * - * @since 2.1 - */ - public static final int INDEX_NOT_FOUND = -1; - - /** - *

- * The maximum size to which the padding constant(s) can expand. - *

- */ - private static final int PAD_LIMIT = 8192; - - /** - * Pattern used in {@link #stripAccents(String)}. - */ - private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$ - - /** - *

- * Abbreviates a String using ellipses. This will turn "Now is the time for all - * good men" into "Now is the time for..." - *

- * - *

- * Specifically: - *

- *
    - *
  • If the number of characters in {@code str} is less than or equal to - * {@code maxWidth}, return {@code str}.
  • - *
  • Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.
  • - *
  • If {@code maxWidth} is less than {@code 4}, throw an - * {@code IllegalArgumentException}.
  • - *
  • In no case will it return a String of length greater than - * {@code maxWidth}.
  • - *
- * - *
-	 * StringUtils.abbreviate(null, *)      = null
-	 * StringUtils.abbreviate("", 4)        = ""
-	 * StringUtils.abbreviate("abcdefg", 6) = "abc..."
-	 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
-	 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
-	 * StringUtils.abbreviate("abcdefg", 4) = "a..."
-	 * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
-	 * 
- * - * @param str the String to check, may be null - * @param maxWidth maximum length of result String, must be at least 4 - * @return abbreviated String, {@code null} if null String input - * @throws IllegalArgumentException if the width is too small - * @since 2.0 - */ - public static String abbreviate(final String str, final int maxWidth) { - return abbreviate(str, "...", 0, maxWidth); - } - - /** - *

- * Abbreviates a String using ellipses. This will turn "Now is the time for all - * good men" into "...is the time for..." - *

- * - *

- * Works like {@code abbreviate(String, int)}, but allows you to specify a "left - * edge" offset. Note that this left edge is not necessarily going to be the - * leftmost character in the result, or the first character following the - * ellipses, but it will appear somewhere in the result. - * - *

- * In no case will it return a String of length greater than {@code maxWidth}. - *

- * - *
-	 * StringUtils.abbreviate(null, *, *)                = null
-	 * StringUtils.abbreviate("", 0, 4)                  = ""
-	 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
-	 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
-	 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
-	 * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
-	 * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
-	 * 
- * - * @param str the String to check, may be null - * @param offset left edge of source String - * @param maxWidth maximum length of result String, must be at least 4 - * @return abbreviated String, {@code null} if null String input - * @throws IllegalArgumentException if the width is too small - * @since 2.0 - */ - public static String abbreviate(final String str, final int offset, final int maxWidth) { - return abbreviate(str, "...", offset, maxWidth); - } - - /** - *

- * Abbreviates a String using another given String as replacement marker. This - * will turn "Now is the time for all good men" into "Now is the time for..." if - * "..." was defined as the replacement marker. - *

- * - *

- * Specifically: - *

- *
    - *
  • If the number of characters in {@code str} is less than or equal to - * {@code maxWidth}, return {@code str}.
  • - *
  • Else abbreviate it to - * {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.
  • - *
  • If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw - * an {@code IllegalArgumentException}.
  • - *
  • In no case will it return a String of length greater than - * {@code maxWidth}.
  • - *
- * - *
-	 * StringUtils.abbreviate(null, "...", *)      = null
-	 * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
-	 * StringUtils.abbreviate("", "...", 4)        = ""
-	 * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
-	 * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
-	 * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
-	 * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
-	 * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
-	 * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
-	 * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
-	 * 
- * - * @param str the String to check, may be null - * @param abbrevMarker the String used as replacement marker - * @param maxWidth maximum length of result String, must be at least - * {@code abbrevMarker.length + 1} - * @return abbreviated String, {@code null} if null String input - * @throws IllegalArgumentException if the width is too small - * @since 3.6 - */ - public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) { - return abbreviate(str, abbrevMarker, 0, maxWidth); - } - - /** - *

- * Abbreviates a String using a given replacement marker. This will turn "Now is - * the time for all good men" into "...is the time for..." if "..." was defined - * as the replacement marker. - *

- * - *

- * Works like {@code abbreviate(String, String, int)}, but allows you to specify - * a "left edge" offset. Note that this left edge is not necessarily going to be - * the leftmost character in the result, or the first character following the - * replacement marker, but it will appear somewhere in the result. - * - *

- * In no case will it return a String of length greater than {@code maxWidth}. - *

- * - *
-	 * StringUtils.abbreviate(null, null, *, *)                 = null
-	 * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
-	 * StringUtils.abbreviate("", "...", 0, 4)                  = ""
-	 * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
-	 * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
-	 * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
-	 * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
-	 * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
-	 * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
-	 * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
-	 * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
-	 * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
-	 * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
-	 * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
-	 * 
- * - * @param str the String to check, may be null - * @param abbrevMarker the String used as replacement marker - * @param offset left edge of source String - * @param maxWidth maximum length of result String, must be at least 4 - * @return abbreviated String, {@code null} if null String input - * @throws IllegalArgumentException if the width is too small - * @since 3.6 - */ - public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) { - if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) { - return substring(str, 0, maxWidth); - } else if (isAnyEmpty(str, abbrevMarker)) { - return str; - } - final int abbrevMarkerLength = abbrevMarker.length(); - final int minAbbrevWidth = abbrevMarkerLength + 1; - final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1; - - if (maxWidth < minAbbrevWidth) { - throw new IllegalArgumentException(HString.format("Minimum abbreviation width is %d", minAbbrevWidth)); - } - final int strLen = str.length(); - if (strLen <= maxWidth) { - return str; - } - if (offset > strLen) { - offset = strLen; - } - if (strLen - offset < maxWidth - abbrevMarkerLength) { - offset = strLen - (maxWidth - abbrevMarkerLength); - } - if (offset <= abbrevMarkerLength + 1) { - return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker; - } - if (maxWidth < minAbbrevWidthOffset) { - throw new IllegalArgumentException( - HString.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset)); - } - if (offset + maxWidth - abbrevMarkerLength < strLen) { - return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength); - } - return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength)); - } - - /** - *

- * Abbreviates a String to the length passed, replacing the middle characters - * with the supplied replacement String. - *

- * - *

- * This abbreviation only occurs if the following criteria is met: - *

- *
    - *
  • Neither the String for abbreviation nor the replacement String are null - * or empty
  • - *
  • The length to truncate to is less than the length of the supplied - * String
  • - *
  • The length to truncate to is greater than 0
  • - *
  • The abbreviated String will have enough room for the length supplied - * replacement String and the first and last characters of the supplied String - * for abbreviation
  • - *
- *

- * Otherwise, the returned String will be the same as the supplied String for - * abbreviation. - *

- * - *
-	 * StringUtils.abbreviateMiddle(null, null, 0)      = null
-	 * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
-	 * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
-	 * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
-	 * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
-	 * 
- * - * @param str the String to abbreviate, may be null - * @param middle the String to replace the middle characters with, may be null - * @param length the length to abbreviate {@code str} to. - * @return the abbreviated String if the above criteria is met, or the original - * String supplied for abbreviation. - * @since 2.5 - */ - public static String abbreviateMiddle(final String str, final String middle, final int length) { - if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) { - return str; - } - - final int targetSting = length - middle.length(); - final int startOffset = targetSting / 2 + targetSting % 2; - final int endOffset = str.length() - targetSting / 2; - - return str.substring(0, startOffset) + middle + str.substring(endOffset); - } - - /** - *

- * Capitalizes a String changing the first character to title case as per - * {@link Character#toTitleCase(int)}. No other characters are changed. - *

- * - *

- * For a word based algorithm, see - * {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}. A - * {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.capitalize(null)  = null
-	 * StringUtils.capitalize("")    = ""
-	 * StringUtils.capitalize("cat") = "Cat"
-	 * StringUtils.capitalize("cAt") = "CAt"
-	 * StringUtils.capitalize("'cat'") = "'cat'"
-	 * 
- * - * @param str the String to capitalize, may be null - * @return the capitalized String, {@code null} if null String input - * @see org.apache.commons.lang3.text.WordUtils#capitalize(String) - * @see #uncapitalize(String) - * @since 2.0 - */ - public static String capitalize(final String str) { - final int strLen = length(str); - if (strLen == 0) { - return str; - } - - final int firstCodepoint = str.codePointAt(0); - final int newCodePoint = Character.toTitleCase(firstCodepoint); - if (firstCodepoint == newCodePoint) { - // already capitalized - return str; - } - - final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array - int outOffset = 0; - newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint - for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen;) { - final int codepoint = str.codePointAt(inOffset); - newCodePoints[outOffset++] = codepoint; // copy the remaining ones - inOffset += Character.charCount(codepoint); - } - return new String(newCodePoints, 0, outOffset); - } - - /** - *

- * Centers a String in a larger String of size {@code size} using the space - * character (' '). - *

- * - *

- * If the size is less than the String length, the original String is returned. - * A {@code null} String returns {@code null}. A negative size is treated as - * zero. - *

- * - *

- * Equivalent to {@code center(str, size, " ")}. - *

- * - *
-	 * StringUtils.center(null, *)   = null
-	 * StringUtils.center("", 4)     = "    "
-	 * StringUtils.center("ab", -1)  = "ab"
-	 * StringUtils.center("ab", 4)   = " ab "
-	 * StringUtils.center("abcd", 2) = "abcd"
-	 * StringUtils.center("a", 4)    = " a  "
-	 * 
- * - * @param str the String to center, may be null - * @param size the int size of new String, negative treated as zero - * @return centered String, {@code null} if null String input - */ - public static String center(final String str, final int size) { - return center(str, size, ' '); - } - - /** - *

- * Centers a String in a larger String of size {@code size}. Uses a supplied - * character as the value to pad the String with. - *

- * - *

- * If the size is less than the String length, the String is returned. A - * {@code null} String returns {@code null}. A negative size is treated as zero. - *

- * - *
-	 * StringUtils.center(null, *, *)     = null
-	 * StringUtils.center("", 4, ' ')     = "    "
-	 * StringUtils.center("ab", -1, ' ')  = "ab"
-	 * StringUtils.center("ab", 4, ' ')   = " ab "
-	 * StringUtils.center("abcd", 2, ' ') = "abcd"
-	 * StringUtils.center("a", 4, ' ')    = " a  "
-	 * StringUtils.center("a", 4, 'y')    = "yayy"
-	 * 
- * - * @param str the String to center, may be null - * @param size the int size of new String, negative treated as zero - * @param padChar the character to pad the new String with - * @return centered String, {@code null} if null String input - * @since 2.0 - */ - public static String center(String str, final int size, final char padChar) { - if (str == null || size <= 0) { - return str; - } - final int strLen = str.length(); - final int pads = size - strLen; - if (pads <= 0) { - return str; - } - str = leftPad(str, strLen + pads / 2, padChar); - str = rightPad(str, size, padChar); - return str; - } - - /** - *

- * Centers a String in a larger String of size {@code size}. Uses a supplied - * String as the value to pad the String with. - *

- * - *

- * If the size is less than the String length, the String is returned. A - * {@code null} String returns {@code null}. A negative size is treated as zero. - *

- * - *
-	 * StringUtils.center(null, *, *)     = null
-	 * StringUtils.center("", 4, " ")     = "    "
-	 * StringUtils.center("ab", -1, " ")  = "ab"
-	 * StringUtils.center("ab", 4, " ")   = " ab "
-	 * StringUtils.center("abcd", 2, " ") = "abcd"
-	 * StringUtils.center("a", 4, " ")    = " a  "
-	 * StringUtils.center("a", 4, "yz")   = "yayz"
-	 * StringUtils.center("abc", 7, null) = "  abc  "
-	 * StringUtils.center("abc", 7, "")   = "  abc  "
-	 * 
- * - * @param str the String to center, may be null - * @param size the int size of new String, negative treated as zero - * @param padStr the String to pad the new String with, must not be null or - * empty - * @return centered String, {@code null} if null String input - * @throws IllegalArgumentException if padStr is {@code null} or empty - */ - public static String center(String str, final int size, String padStr) { - if (str == null || size <= 0) { - return str; - } - if (isEmpty(padStr)) { - padStr = SPACE; - } - final int strLen = str.length(); - final int pads = size - strLen; - if (pads <= 0) { - return str; - } - str = leftPad(str, strLen + pads / 2, padStr); - str = rightPad(str, size, padStr); - return str; - } - - /** - *

- * Removes one newline from end of a String if it's there, otherwise leave it - * alone. A newline is "{@code \n}", "{@code \r}", or - * "{@code \r\n}". - *

- * - *

- * NOTE: This method changed in 2.0. It now more closely matches Perl chomp. - *

- * - *
-	 * StringUtils.chomp(null)          = null
-	 * StringUtils.chomp("")            = ""
-	 * StringUtils.chomp("abc \r")      = "abc "
-	 * StringUtils.chomp("abc\n")       = "abc"
-	 * StringUtils.chomp("abc\r\n")     = "abc"
-	 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
-	 * StringUtils.chomp("abc\n\r")     = "abc\n"
-	 * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
-	 * StringUtils.chomp("\r")          = ""
-	 * StringUtils.chomp("\n")          = ""
-	 * StringUtils.chomp("\r\n")        = ""
-	 * 
- * - * @param str the String to chomp a newline from, may be null - * @return String without newline, {@code null} if null String input - */ - public static String chomp(final String str) { - if (isEmpty(str)) { - return str; - } - - if (str.length() == 1) { - final char ch = str.charAt(0); - if (ch == CharUtils.CR || ch == CharUtils.LF) { - return EMPTY; - } - return str; - } - - int lastIdx = str.length() - 1; - final char last = str.charAt(lastIdx); - - if (last == CharUtils.LF) { - if (str.charAt(lastIdx - 1) == CharUtils.CR) { - lastIdx--; - } - } else if (last != CharUtils.CR) { - lastIdx++; - } - return str.substring(0, lastIdx); - } - - /** - *

- * Removes {@code separator} from the end of {@code str} if it's there, - * otherwise leave it alone. - *

- * - *

- * NOTE: This method changed in version 2.0. It now more closely matches Perl - * chomp. For the previous behavior, use - * {@link #substringBeforeLast(String, String)}. This method uses - * {@link String#endsWith(String)}. - *

- * - *
-	 * StringUtils.chomp(null, *)         = null
-	 * StringUtils.chomp("", *)           = ""
-	 * StringUtils.chomp("foobar", "bar") = "foo"
-	 * StringUtils.chomp("foobar", "baz") = "foobar"
-	 * StringUtils.chomp("foo", "foo")    = ""
-	 * StringUtils.chomp("foo ", "foo")   = "foo "
-	 * StringUtils.chomp(" foo", "foo")   = " "
-	 * StringUtils.chomp("foo", "foooo")  = "foo"
-	 * StringUtils.chomp("foo", "")       = "foo"
-	 * StringUtils.chomp("foo", null)     = "foo"
-	 * 
- * - * @param str the String to chomp from, may be null - * @param separator separator String, may be null - * @return String without trailing separator, {@code null} if null String input - * @deprecated This feature will be removed in Lang 4.0, use - * {@link StringUtils#removeEnd(String, String)} instead - */ - @Deprecated - public static String chomp(final String str, final String separator) { - return removeEnd(str, separator); - } - - /** - *

- * Remove the last character from a String. - *

- * - *

- * If the String ends in {@code \r\n}, then remove both of them. - *

- * - *
-	 * StringUtils.chop(null)          = null
-	 * StringUtils.chop("")            = ""
-	 * StringUtils.chop("abc \r")      = "abc "
-	 * StringUtils.chop("abc\n")       = "abc"
-	 * StringUtils.chop("abc\r\n")     = "abc"
-	 * StringUtils.chop("abc")         = "ab"
-	 * StringUtils.chop("abc\nabc")    = "abc\nab"
-	 * StringUtils.chop("a")           = ""
-	 * StringUtils.chop("\r")          = ""
-	 * StringUtils.chop("\n")          = ""
-	 * StringUtils.chop("\r\n")        = ""
-	 * 
- * - * @param str the String to chop last character from, may be null - * @return String without last character, {@code null} if null String input - */ - public static String chop(final String str) { - if (str == null) { - return null; - } - final int strLen = str.length(); - if (strLen < 2) { - return EMPTY; - } - final int lastIdx = strLen - 1; - final String ret = str.substring(0, lastIdx); - final char last = str.charAt(lastIdx); - if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) { - return ret.substring(0, lastIdx - 1); - } - return ret; - } - - /** - *

- * Compare two Strings lexicographically, as per - * {@link String#compareTo(String)}, returning : - *

- *
    - *
  • {@code int = 0}, if {@code str1} is equal to {@code str2} (or both - * {@code null})
  • - *
  • {@code int < 0}, if {@code str1} is less than {@code str2}
  • - *
  • {@code int > 0}, if {@code str1} is greater than {@code str2}
  • - *
- * - *

- * This is a {@code null} safe version of : - *

- *
- * - *
-	 * str1.compareTo(str2)
-	 * 
- * - *
- * - *

- * {@code null} value is considered less than non-{@code null} value. Two - * {@code null} references are considered equal. - *

- * - *
-	 * StringUtils.compare(null, null)   = 0
-	 * StringUtils.compare(null , "a")   < 0
-	 * StringUtils.compare("a", null)    > 0
-	 * StringUtils.compare("abc", "abc") = 0
-	 * StringUtils.compare("a", "b")     < 0
-	 * StringUtils.compare("b", "a")     > 0
-	 * StringUtils.compare("a", "B")     > 0
-	 * StringUtils.compare("ab", "abc")  < 0
-	 * 
- * - * @see #compare(String, String, boolean) - * @see String#compareTo(String) - * @param str1 the String to compare from - * @param str2 the String to compare to - * @return < 0, 0, > 0, if {@code str1} is respectively less, equal or - * greater than {@code str2} - * @since 3.5 - */ - public static int compare(final String str1, final String str2) { - return compare(str1, str2, true); - } - - /** - *

- * Compare two Strings lexicographically, as per - * {@link String#compareTo(String)}, returning : - *

- *
    - *
  • {@code int = 0}, if {@code str1} is equal to {@code str2} (or both - * {@code null})
  • - *
  • {@code int < 0}, if {@code str1} is less than {@code str2}
  • - *
  • {@code int > 0}, if {@code str1} is greater than {@code str2}
  • - *
- * - *

- * This is a {@code null} safe version of : - *

- *
- * - *
-	 * str1.compareTo(str2)
-	 * 
- * - *
- * - *

- * {@code null} inputs are handled according to the {@code nullIsLess} - * parameter. Two {@code null} references are considered equal. - *

- * - *
-	 * StringUtils.compare(null, null, *)     = 0
-	 * StringUtils.compare(null , "a", true)  < 0
-	 * StringUtils.compare(null , "a", false) > 0
-	 * StringUtils.compare("a", null, true)   > 0
-	 * StringUtils.compare("a", null, false)  < 0
-	 * StringUtils.compare("abc", "abc", *)   = 0
-	 * StringUtils.compare("a", "b", *)       < 0
-	 * StringUtils.compare("b", "a", *)       > 0
-	 * StringUtils.compare("a", "B", *)       > 0
-	 * StringUtils.compare("ab", "abc", *)    < 0
-	 * 
- * - * @see String#compareTo(String) - * @param str1 the String to compare from - * @param str2 the String to compare to - * @param nullIsLess whether consider {@code null} value less than - * non-{@code null} value - * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou - * greater than {@code str2} - * @since 3.5 - */ - public static int compare(final String str1, final String str2, final boolean nullIsLess) { - if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null - return 0; - } - if (str1 == null) { - return nullIsLess ? -1 : 1; - } - if (str2 == null) { - return nullIsLess ? 1 : -1; - } - return str1.compareTo(str2); - } - - /** - *

- * Compare two Strings lexicographically, ignoring case differences, as per - * {@link String#compareToIgnoreCase(String)}, returning : - *

- *
    - *
  • {@code int = 0}, if {@code str1} is equal to {@code str2} (or both - * {@code null})
  • - *
  • {@code int < 0}, if {@code str1} is less than {@code str2}
  • - *
  • {@code int > 0}, if {@code str1} is greater than {@code str2}
  • - *
- * - *

- * This is a {@code null} safe version of : - *

- *
- * - *
-	 * str1.compareToIgnoreCase(str2)
-	 * 
- * - *
- * - *

- * {@code null} value is considered less than non-{@code null} value. Two - * {@code null} references are considered equal. Comparison is case insensitive. - *

- * - *
-	 * StringUtils.compareIgnoreCase(null, null)   = 0
-	 * StringUtils.compareIgnoreCase(null , "a")   < 0
-	 * StringUtils.compareIgnoreCase("a", null)    > 0
-	 * StringUtils.compareIgnoreCase("abc", "abc") = 0
-	 * StringUtils.compareIgnoreCase("abc", "ABC") = 0
-	 * StringUtils.compareIgnoreCase("a", "b")     < 0
-	 * StringUtils.compareIgnoreCase("b", "a")     > 0
-	 * StringUtils.compareIgnoreCase("a", "B")     < 0
-	 * StringUtils.compareIgnoreCase("A", "b")     < 0
-	 * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
-	 * 
- * - * @see #compareIgnoreCase(String, String, boolean) - * @see String#compareToIgnoreCase(String) - * @param str1 the String to compare from - * @param str2 the String to compare to - * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou - * greater than {@code str2}, ignoring case differences. - * @since 3.5 - */ - public static int compareIgnoreCase(final String str1, final String str2) { - return compareIgnoreCase(str1, str2, true); - } - - /** - *

- * Compare two Strings lexicographically, ignoring case differences, as per - * {@link String#compareToIgnoreCase(String)}, returning : - *

- *
    - *
  • {@code int = 0}, if {@code str1} is equal to {@code str2} (or both - * {@code null})
  • - *
  • {@code int < 0}, if {@code str1} is less than {@code str2}
  • - *
  • {@code int > 0}, if {@code str1} is greater than {@code str2}
  • - *
- * - *

- * This is a {@code null} safe version of : - *

- *
- * - *
-	 * str1.compareToIgnoreCase(str2)
-	 * 
- * - *
- * - *

- * {@code null} inputs are handled according to the {@code nullIsLess} - * parameter. Two {@code null} references are considered equal. Comparison is - * case insensitive. - *

- * - *
-	 * StringUtils.compareIgnoreCase(null, null, *)     = 0
-	 * StringUtils.compareIgnoreCase(null , "a", true)  < 0
-	 * StringUtils.compareIgnoreCase(null , "a", false) > 0
-	 * StringUtils.compareIgnoreCase("a", null, true)   > 0
-	 * StringUtils.compareIgnoreCase("a", null, false)  < 0
-	 * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
-	 * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
-	 * StringUtils.compareIgnoreCase("a", "b", *)       < 0
-	 * StringUtils.compareIgnoreCase("b", "a", *)       > 0
-	 * StringUtils.compareIgnoreCase("a", "B", *)       < 0
-	 * StringUtils.compareIgnoreCase("A", "b", *)       < 0
-	 * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
-	 * 
- * - * @see String#compareToIgnoreCase(String) - * @param str1 the String to compare from - * @param str2 the String to compare to - * @param nullIsLess whether consider {@code null} value less than - * non-{@code null} value - * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou - * greater than {@code str2}, ignoring case differences. - * @since 3.5 - */ - public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) { - if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null - return 0; - } - if (str1 == null) { - return nullIsLess ? -1 : 1; - } - if (str2 == null) { - return nullIsLess ? 1 : -1; - } - return str1.compareToIgnoreCase(str2); - } - - /** - *

- * Checks if CharSequence contains a search CharSequence, handling {@code null}. - * This method uses {@link String#indexOf(String)} if possible. - *

- * - *

- * A {@code null} CharSequence will return {@code false}. - *

- * - *
-	 * StringUtils.contains(null, *)     = false
-	 * StringUtils.contains(*, null)     = false
-	 * StringUtils.contains("", "")      = true
-	 * StringUtils.contains("abc", "")   = true
-	 * StringUtils.contains("abc", "a")  = true
-	 * StringUtils.contains("abc", "z")  = false
-	 * 
- * - * @param seq the CharSequence to check, may be null - * @param searchSeq the CharSequence to find, may be null - * @return true if the CharSequence contains the search CharSequence, false if - * not or {@code null} string input - * @since 2.0 - * @since 3.0 Changed signature from contains(String, String) to - * contains(CharSequence, CharSequence) - */ - public static boolean contains(final CharSequence seq, final CharSequence searchSeq) { - if (seq == null || searchSeq == null) { - return false; - } - return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0; - } - - /** - *

- * Checks if CharSequence contains a search character, handling {@code null}. - * This method uses {@link String#indexOf(int)} if possible. - *

- * - *

- * A {@code null} or empty ("") CharSequence will return {@code false}. - *

- * - *
-	 * StringUtils.contains(null, *)    = false
-	 * StringUtils.contains("", *)      = false
-	 * StringUtils.contains("abc", 'a') = true
-	 * StringUtils.contains("abc", 'z') = false
-	 * 
- * - * @param seq the CharSequence to check, may be null - * @param searchChar the character to find - * @return true if the CharSequence contains the search character, false if not - * or {@code null} string input - * @since 2.0 - * @since 3.0 Changed signature from contains(String, int) to - * contains(CharSequence, int) - */ - public static boolean contains(final CharSequence seq, final int searchChar) { - if (isEmpty(seq)) { - return false; - } - return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0; - } - - /** - *

- * Checks if the CharSequence contains any character in the given set of - * characters. - *

- * - *

- * A {@code null} CharSequence will return {@code false}. A {@code null} or zero - * length search array will return {@code false}. - *

- * - *
-	 * StringUtils.containsAny(null, *)                  = false
-	 * StringUtils.containsAny("", *)                    = false
-	 * StringUtils.containsAny(*, null)                  = false
-	 * StringUtils.containsAny(*, [])                    = false
-	 * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
-	 * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
-	 * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
-	 * StringUtils.containsAny("aba", ['z'])             = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @param searchChars the chars to search for, may be null - * @return the {@code true} if any of the chars are found, {@code false} if no - * match or null input - * @since 2.4 - * @since 3.0 Changed signature from containsAny(String, char[]) to - * containsAny(CharSequence, char...) - */ - public static boolean containsAny(final CharSequence cs, final char... searchChars) { - if (isEmpty(cs) || searchChars.length == 0) { - return false; - } - final int csLength = cs.length(); - final int searchLength = searchChars.length; - final int csLast = csLength - 1; - final int searchLast = searchLength - 1; - for (int i = 0; i < csLength; i++) { - final char ch = cs.charAt(i); - for (int j = 0; j < searchLength; j++) { - if (searchChars[j] == ch) { - if (Character.isHighSurrogate(ch)) { - if (j == searchLast) { - // missing low surrogate, fine, like String.indexOf(String) - return true; - } - if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { - return true; - } - } else { - // ch is in the Basic Multilingual Plane - return true; - } - } - } - } - return false; - } - - /** - *

- * Checks if the CharSequence contains any character in the given set of - * characters. - *

- * - *

- * A {@code null} CharSequence will return {@code false}. A {@code null} search - * CharSequence will return {@code false}. - *

- * - *
-	 * StringUtils.containsAny(null, *)               = false
-	 * StringUtils.containsAny("", *)                 = false
-	 * StringUtils.containsAny(*, null)               = false
-	 * StringUtils.containsAny(*, "")                 = false
-	 * StringUtils.containsAny("zzabyycdxx", "za")    = true
-	 * StringUtils.containsAny("zzabyycdxx", "by")    = true
-	 * StringUtils.containsAny("zzabyycdxx", "zy")    = true
-	 * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
-	 * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
-	 * StringUtils.containsAny("aba", "z")            = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @param searchChars the chars to search for, may be null - * @return the {@code true} if any of the chars are found, {@code false} if no - * match or null input - * @since 2.4 - * @since 3.0 Changed signature from containsAny(String, String) to - * containsAny(CharSequence, CharSequence) - */ - public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) { - if (searchChars == null) { - return false; - } - return containsAny(cs, CharSequenceUtils.toCharArray(searchChars)); - } - - /** - *

- * Checks if the CharSequence contains any of the CharSequences in the given - * array. - *

- * - *

- * A {@code null} {@code cs} CharSequence will return {@code false}. A - * {@code null} or zero length search array will return {@code false}. - *

- * - *
-	 * StringUtils.containsAny(null, *)            = false
-	 * StringUtils.containsAny("", *)              = false
-	 * StringUtils.containsAny(*, null)            = false
-	 * StringUtils.containsAny(*, [])              = false
-	 * StringUtils.containsAny("abcd", "ab", null) = true
-	 * StringUtils.containsAny("abcd", "ab", "cd") = true
-	 * StringUtils.containsAny("abc", "d", "abc")  = true
-	 * 
- * - * - * @param cs The CharSequence to check, may be null - * @param searchCharSequences The array of CharSequences to search for, may be - * null. Individual CharSequences may be null as - * well. - * @return {@code true} if any of the search CharSequences are found, - * {@code false} otherwise - * @since 3.4 - */ - public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) { - return containsAny(StringUtils::contains, cs, searchCharSequences); - } - - /** - *

- * Checks if the CharSequence contains any of the CharSequences in the given - * array. - *

- * - *

- * A {@code null} {@code cs} CharSequence will return {@code false}. A - * {@code null} or zero length search array will return {@code false}. - *

- * - * @param cs The CharSequence to check, may be null - * @param searchCharSequences The array of CharSequences to search for, may be - * null. Individual CharSequences may be null as - * well. - * @return {@code true} if any of the search CharSequences are found, - * {@code false} otherwise - * @since 3.12.0 - */ - private static boolean containsAny(final ToBooleanBiFunction test, - final CharSequence cs, final CharSequence... searchCharSequences) { - if (isEmpty(cs) || searchCharSequences.length == 0) { - return false; - } - for (final CharSequence searchCharSequence : searchCharSequences) { - if (test.applyAsBoolean(cs, searchCharSequence)) { - return true; - } - } - return false; - } - - /** - *

- * Checks if the CharSequence contains any of the CharSequences in the given - * array, ignoring case. - *

- * - *

- * A {@code null} {@code cs} CharSequence will return {@code false}. A - * {@code null} or zero length search array will return {@code false}. - *

- * - *
-	 * StringUtils.containsAny(null, *)            = false
-	 * StringUtils.containsAny("", *)              = false
-	 * StringUtils.containsAny(*, null)            = false
-	 * StringUtils.containsAny(*, [])              = false
-	 * StringUtils.containsAny("abcd", "ab", null) = true
-	 * StringUtils.containsAny("abcd", "ab", "cd") = true
-	 * StringUtils.containsAny("abc", "d", "abc")  = true
-	 * StringUtils.containsAny("abc", "D", "ABC")  = true
-	 * StringUtils.containsAny("ABC", "d", "abc")  = true
-	 * 
- * - * - * @param cs The CharSequence to check, may be null - * @param searchCharSequences The array of CharSequences to search for, may be - * null. Individual CharSequences may be null as - * well. - * @return {@code true} if any of the search CharSequences are found, - * {@code false} otherwise - * @since 3.12.0 - */ - public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) { - return containsAny(StringUtils::containsIgnoreCase, cs, searchCharSequences); - } - - /** - *

- * Checks if CharSequence contains a search CharSequence irrespective of case, - * handling {@code null}. Case-insensitivity is defined as by - * {@link String#equalsIgnoreCase(String)}. - * - *

- * A {@code null} CharSequence will return {@code false}. - *

- * - *
-	 * StringUtils.containsIgnoreCase(null, *) = false
-	 * StringUtils.containsIgnoreCase(*, null) = false
-	 * StringUtils.containsIgnoreCase("", "") = true
-	 * StringUtils.containsIgnoreCase("abc", "") = true
-	 * StringUtils.containsIgnoreCase("abc", "a") = true
-	 * StringUtils.containsIgnoreCase("abc", "z") = false
-	 * StringUtils.containsIgnoreCase("abc", "A") = true
-	 * StringUtils.containsIgnoreCase("abc", "Z") = false
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @return true if the CharSequence contains the search CharSequence - * irrespective of case or false if not or {@code null} string input - * @since 3.0 Changed signature from containsIgnoreCase(String, String) to - * containsIgnoreCase(CharSequence, CharSequence) - */ - public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) { - if (str == null || searchStr == null) { - return false; - } - final int len = searchStr.length(); - final int max = str.length() - len; - for (int i = 0; i <= max; i++) { - if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) { - return true; - } - } - return false; - } - - /** - *

- * Checks that the CharSequence does not contain certain characters. - *

- * - *

- * A {@code null} CharSequence will return {@code true}. A {@code null} invalid - * character array will return {@code true}. An empty CharSequence (length()=0) - * always returns true. - *

- * - *
-	 * StringUtils.containsNone(null, *)       = true
-	 * StringUtils.containsNone(*, null)       = true
-	 * StringUtils.containsNone("", *)         = true
-	 * StringUtils.containsNone("ab", '')      = true
-	 * StringUtils.containsNone("abab", 'xyz') = true
-	 * StringUtils.containsNone("ab1", 'xyz')  = true
-	 * StringUtils.containsNone("abz", 'xyz')  = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @param searchChars an array of invalid chars, may be null - * @return true if it contains none of the invalid chars, or is null - * @since 2.0 - * @since 3.0 Changed signature from containsNone(String, char[]) to - * containsNone(CharSequence, char...) - */ - public static boolean containsNone(final CharSequence cs, final char... searchChars) { - if (cs == null || searchChars == null) { - return true; - } - final int csLen = cs.length(); - final int csLast = csLen - 1; - final int searchLen = searchChars.length; - final int searchLast = searchLen - 1; - for (int i = 0; i < csLen; i++) { - final char ch = cs.charAt(i); - for (int j = 0; j < searchLen; j++) { - if (searchChars[j] == ch) { - if (Character.isHighSurrogate(ch)) { - if (j == searchLast) { - // missing low surrogate, fine, like String.indexOf(String) - return false; - } - if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { - return false; - } - } else { - // ch is in the Basic Multilingual Plane - return false; - } - } - } - } - return true; - } - - /** - *

- * Checks that the CharSequence does not contain certain characters. - *

- * - *

- * A {@code null} CharSequence will return {@code true}. A {@code null} invalid - * character array will return {@code true}. An empty String ("") always returns - * true. - *

- * - *
-	 * StringUtils.containsNone(null, *)       = true
-	 * StringUtils.containsNone(*, null)       = true
-	 * StringUtils.containsNone("", *)         = true
-	 * StringUtils.containsNone("ab", "")      = true
-	 * StringUtils.containsNone("abab", "xyz") = true
-	 * StringUtils.containsNone("ab1", "xyz")  = true
-	 * StringUtils.containsNone("abz", "xyz")  = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @param invalidChars a String of invalid chars, may be null - * @return true if it contains none of the invalid chars, or is null - * @since 2.0 - * @since 3.0 Changed signature from containsNone(String, String) to - * containsNone(CharSequence, String) - */ - public static boolean containsNone(final CharSequence cs, final String invalidChars) { - if (invalidChars == null) { - return true; - } - return containsNone(cs, invalidChars.toCharArray()); - } - - /** - *

- * Checks if the CharSequence contains only certain characters. - *

- * - *

- * A {@code null} CharSequence will return {@code false}. A {@code null} valid - * character array will return {@code false}. An empty CharSequence (length()=0) - * always returns {@code true}. - *

- * - *
-	 * StringUtils.containsOnly(null, *)       = false
-	 * StringUtils.containsOnly(*, null)       = false
-	 * StringUtils.containsOnly("", *)         = true
-	 * StringUtils.containsOnly("ab", '')      = false
-	 * StringUtils.containsOnly("abab", 'abc') = true
-	 * StringUtils.containsOnly("ab1", 'abc')  = false
-	 * StringUtils.containsOnly("abz", 'abc')  = false
-	 * 
- * - * @param cs the String to check, may be null - * @param valid an array of valid chars, may be null - * @return true if it only contains valid chars and is non-null - * @since 3.0 Changed signature from containsOnly(String, char[]) to - * containsOnly(CharSequence, char...) - */ - public static boolean containsOnly(final CharSequence cs, final char... valid) { - // All these pre-checks are to maintain API with an older version - if (valid == null || cs == null) { - return false; - } - if (cs.length() == 0) { - return true; - } - if (valid.length == 0) { - return false; - } - return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND; - } - - /** - *

- * Checks if the CharSequence contains only certain characters. - *

- * - *

- * A {@code null} CharSequence will return {@code false}. A {@code null} valid - * character String will return {@code false}. An empty String (length()=0) - * always returns {@code true}. - *

- * - *
-	 * StringUtils.containsOnly(null, *)       = false
-	 * StringUtils.containsOnly(*, null)       = false
-	 * StringUtils.containsOnly("", *)         = true
-	 * StringUtils.containsOnly("ab", "")      = false
-	 * StringUtils.containsOnly("abab", "abc") = true
-	 * StringUtils.containsOnly("ab1", "abc")  = false
-	 * StringUtils.containsOnly("abz", "abc")  = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @param validChars a String of valid chars, may be null - * @return true if it only contains valid chars and is non-null - * @since 2.0 - * @since 3.0 Changed signature from containsOnly(String, String) to - * containsOnly(CharSequence, String) - */ - public static boolean containsOnly(final CharSequence cs, final String validChars) { - if (cs == null || validChars == null) { - return false; - } - return containsOnly(cs, validChars.toCharArray()); - } - - /** - *

- * Check whether the given CharSequence contains any whitespace characters. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - * @param seq the CharSequence to check (may be {@code null}) - * @return {@code true} if the CharSequence is not empty and contains at least 1 - * (breaking) whitespace character - * @since 3.0 - */ - // From org.springframework.util.StringUtils, under Apache License 2.0 - public static boolean containsWhitespace(final CharSequence seq) { - if (isEmpty(seq)) { - return false; - } - final int strLen = seq.length(); - for (int i = 0; i < strLen; i++) { - if (Character.isWhitespace(seq.charAt(i))) { - return true; - } - } - return false; - } - - private static void convertRemainingAccentCharacters(final StringBuilder decomposed) { - for (int i = 0; i < decomposed.length(); i++) { - if (decomposed.charAt(i) == '\u0141') { - decomposed.setCharAt(i, 'L'); - } else if (decomposed.charAt(i) == '\u0142') { - decomposed.setCharAt(i, 'l'); - } - } - } - - /** - *

- * Counts how many times the char appears in the given string. - *

- * - *

- * A {@code null} or empty ("") String input returns {@code 0}. - *

- * - *
-	 * StringUtils.countMatches(null, *)       = 0
-	 * StringUtils.countMatches("", *)         = 0
-	 * StringUtils.countMatches("abba", 0)  = 0
-	 * StringUtils.countMatches("abba", 'a')   = 2
-	 * StringUtils.countMatches("abba", 'b')  = 2
-	 * StringUtils.countMatches("abba", 'x') = 0
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param ch the char to count - * @return the number of occurrences, 0 if the CharSequence is {@code null} - * @since 3.4 - */ - public static int countMatches(final CharSequence str, final char ch) { - if (isEmpty(str)) { - return 0; - } - int count = 0; - // We could also call str.toCharArray() for faster look ups but that would - // generate more garbage. - for (int i = 0; i < str.length(); i++) { - if (ch == str.charAt(i)) { - count++; - } - } - return count; - } - - /** - *

- * Counts how many times the substring appears in the larger string. Note that - * the code only counts non-overlapping matches. - *

- * - *

- * A {@code null} or empty ("") String input returns {@code 0}. - *

- * - *
-	 * StringUtils.countMatches(null, *)       = 0
-	 * StringUtils.countMatches("", *)         = 0
-	 * StringUtils.countMatches("abba", null)  = 0
-	 * StringUtils.countMatches("abba", "")    = 0
-	 * StringUtils.countMatches("abba", "a")   = 2
-	 * StringUtils.countMatches("abba", "ab")  = 1
-	 * StringUtils.countMatches("abba", "xxx") = 0
-	 * StringUtils.countMatches("ababa", "aba") = 1
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param sub the substring to count, may be null - * @return the number of occurrences, 0 if either CharSequence is {@code null} - * @since 3.0 Changed signature from countMatches(String, String) to - * countMatches(CharSequence, CharSequence) - */ - public static int countMatches(final CharSequence str, final CharSequence sub) { - if (isEmpty(str) || isEmpty(sub)) { - return 0; - } - int count = 0; - int idx = 0; - while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) { - count++; - idx += sub.length(); - } - return count; - } - - /** - *

- * Returns either the passed in CharSequence, or if the CharSequence is - * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
-	 * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
-	 * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
-	 * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
-	 * StringUtils.defaultIfBlank("", null)      = null
-	 * 
- * - * @param the specific kind of CharSequence - * @param str the CharSequence to check, may be null - * @param defaultStr the default CharSequence to return if the input is - * whitespace, empty ("") or {@code null}, may be null - * @return the passed in CharSequence, or the default - * @see StringUtils#defaultString(String, String) - */ - public static T defaultIfBlank(final T str, final T defaultStr) { - return isBlank(str) ? defaultStr : str; - } - - /** - *

- * Returns either the passed in CharSequence, or if the CharSequence is empty or - * {@code null}, the value of {@code defaultStr}. - *

- * - *
-	 * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
-	 * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
-	 * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
-	 * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
-	 * StringUtils.defaultIfEmpty("", null)      = null
-	 * 
- * - * @param the specific kind of CharSequence - * @param str the CharSequence to check, may be null - * @param defaultStr the default CharSequence to return if the input is empty - * ("") or {@code null}, may be null - * @return the passed in CharSequence, or the default - * @see StringUtils#defaultString(String, String) - */ - public static T defaultIfEmpty(final T str, final T defaultStr) { - return isEmpty(str) ? defaultStr : str; - } - - /** - *

- * Returns either the passed in String, or if the String is {@code null}, an - * empty String (""). - *

- * - *
-	 * StringUtils.defaultString(null)  = ""
-	 * StringUtils.defaultString("")    = ""
-	 * StringUtils.defaultString("bat") = "bat"
-	 * 
- * - * @see ObjectUtils#toString(Object) - * @see String#valueOf(Object) - * @param str the String to check, may be null - * @return the passed in String, or the empty String if it was {@code null} - */ - public static String defaultString(final String str) { - return defaultString(str, EMPTY); - } - - /** - *

- * Returns either the passed in String, or if the String is {@code null}, the - * value of {@code defaultStr}. - *

- * - *
-	 * StringUtils.defaultString(null, "NULL")  = "NULL"
-	 * StringUtils.defaultString("", "NULL")    = ""
-	 * StringUtils.defaultString("bat", "NULL") = "bat"
-	 * 
- * - * @see ObjectUtils#toString(Object,String) - * @see String#valueOf(Object) - * @param str the String to check, may be null - * @param defaultStr the default String to return if the input is {@code null}, - * may be null - * @return the passed in String, or the default if it was {@code null} - */ - public static String defaultString(final String str, final String defaultStr) { - return str == null ? defaultStr : str; - } - - /** - *

- * Deletes all whitespaces from a String as defined by - * {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.deleteWhitespace(null)         = null
-	 * StringUtils.deleteWhitespace("")           = ""
-	 * StringUtils.deleteWhitespace("abc")        = "abc"
-	 * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
-	 * 
- * - * @param str the String to delete whitespace from, may be null - * @return the String without whitespaces, {@code null} if null String input - */ - public static String deleteWhitespace(final String str) { - if (isEmpty(str)) { - return str; - } - final int sz = str.length(); - final char[] chs = new char[sz]; - int count = 0; - for (int i = 0; i < sz; i++) { - if (!Character.isWhitespace(str.charAt(i))) { - chs[count++] = str.charAt(i); - } - } - if (count == sz) { - return str; - } - if (count == 0) { - return EMPTY; - } - return new String(chs, 0, count); - } - - /** - *

- * Compares two Strings, and returns the portion where they differ. More - * precisely, return the remainder of the second String, starting from where - * it's different from the first. This means that the difference between "abc" - * and "ab" is the empty String and not "c". - *

- * - *

- * For example, {@code difference("i am a machine", "i am a robot") -> "robot"}. - *

- * - *
-	 * StringUtils.difference(null, null) = null
-	 * StringUtils.difference("", "") = ""
-	 * StringUtils.difference("", "abc") = "abc"
-	 * StringUtils.difference("abc", "") = ""
-	 * StringUtils.difference("abc", "abc") = ""
-	 * StringUtils.difference("abc", "ab") = ""
-	 * StringUtils.difference("ab", "abxyz") = "xyz"
-	 * StringUtils.difference("abcde", "abxyz") = "xyz"
-	 * StringUtils.difference("abcde", "xyz") = "xyz"
-	 * 
- * - * @param str1 the first String, may be null - * @param str2 the second String, may be null - * @return the portion of str2 where it differs from str1; returns the empty - * String if they are equal - * @see #indexOfDifference(CharSequence,CharSequence) - * @since 2.0 - */ - public static String difference(final String str1, final String str2) { - if (str1 == null) { - return str2; - } - if (str2 == null) { - return str1; - } - final int at = indexOfDifference(str1, str2); - if (at == INDEX_NOT_FOUND) { - return EMPTY; - } - return str2.substring(at); - } - - /** - *

- * Check if a CharSequence ends with a specified suffix. - *

- * - *

- * {@code null}s are handled without exceptions. Two {@code null} references are - * considered to be equal. The comparison is case sensitive. - *

- * - *
-	 * StringUtils.endsWith(null, null)      = true
-	 * StringUtils.endsWith(null, "def")     = false
-	 * StringUtils.endsWith("abcdef", null)  = false
-	 * StringUtils.endsWith("abcdef", "def") = true
-	 * StringUtils.endsWith("ABCDEF", "def") = false
-	 * StringUtils.endsWith("ABCDEF", "cde") = false
-	 * StringUtils.endsWith("ABCDEF", "")    = true
-	 * 
- * - * @see java.lang.String#endsWith(String) - * @param str the CharSequence to check, may be null - * @param suffix the suffix to find, may be null - * @return {@code true} if the CharSequence ends with the suffix, case - * sensitive, or both {@code null} - * @since 2.4 - * @since 3.0 Changed signature from endsWith(String, String) to - * endsWith(CharSequence, CharSequence) - */ - public static boolean endsWith(final CharSequence str, final CharSequence suffix) { - return endsWith(str, suffix, false); - } - - /** - *

- * Check if a CharSequence ends with a specified suffix (optionally case - * insensitive). - *

- * - * @see java.lang.String#endsWith(String) - * @param str the CharSequence to check, may be null - * @param suffix the suffix to find, may be null - * @param ignoreCase indicates whether the compare should ignore case (case - * insensitive) or not. - * @return {@code true} if the CharSequence starts with the prefix or both - * {@code null} - */ - private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) { - if (str == null || suffix == null) { - return str == suffix; - } - if (suffix.length() > str.length()) { - return false; - } - final int strOffset = str.length() - suffix.length(); - return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); - } - - /** - *

- * Check if a CharSequence ends with any of the provided case-sensitive - * suffixes. - *

- * - *
-	 * StringUtils.endsWithAny(null, null)      = false
-	 * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
-	 * StringUtils.endsWithAny("abcxyz", null)     = false
-	 * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
-	 * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
-	 * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
-	 * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
-	 * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
-	 * 
- * - * @param sequence the CharSequence to check, may be null - * @param searchStrings the case-sensitive CharSequences to find, may be empty - * or contain {@code null} - * @see StringUtils#endsWith(CharSequence, CharSequence) - * @return {@code true} if the input {@code sequence} is {@code null} AND no - * {@code searchStrings} are provided, or the input {@code sequence} - * ends in any of the provided case-sensitive {@code searchStrings}. - * @since 3.0 - */ - public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { - if (isEmpty(sequence) || searchStrings.length == 0) { - return false; - } - for (final CharSequence searchString : searchStrings) { - if (endsWith(sequence, searchString)) { - return true; - } - } - return false; - } - - /** - *

- * Case insensitive check if a CharSequence ends with a specified suffix. - *

- * - *

- * {@code null}s are handled without exceptions. Two {@code null} references are - * considered to be equal. The comparison is case insensitive. - *

- * - *
-	 * StringUtils.endsWithIgnoreCase(null, null)      = true
-	 * StringUtils.endsWithIgnoreCase(null, "def")     = false
-	 * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
-	 * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
-	 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
-	 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
-	 * 
- * - * @see java.lang.String#endsWith(String) - * @param str the CharSequence to check, may be null - * @param suffix the suffix to find, may be null - * @return {@code true} if the CharSequence ends with the suffix, case - * insensitive, or both {@code null} - * @since 2.4 - * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to - * endsWithIgnoreCase(CharSequence, CharSequence) - */ - public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) { - return endsWith(str, suffix, true); - } - - /** - *

- * Compares two CharSequences, returning {@code true} if they represent equal - * sequences of characters. - *

- * - *

- * {@code null}s are handled without exceptions. Two {@code null} references are - * considered to be equal. The comparison is case sensitive. - *

- * - *
-	 * StringUtils.equals(null, null)   = true
-	 * StringUtils.equals(null, "abc")  = false
-	 * StringUtils.equals("abc", null)  = false
-	 * StringUtils.equals("abc", "abc") = true
-	 * StringUtils.equals("abc", "ABC") = false
-	 * 
- * - * @param cs1 the first CharSequence, may be {@code null} - * @param cs2 the second CharSequence, may be {@code null} - * @return {@code true} if the CharSequences are equal (case-sensitive), or both - * {@code null} - * @since 3.0 Changed signature from equals(String, String) to - * equals(CharSequence, CharSequence) - * @see Object#equals(Object) - * @see #equalsIgnoreCase(CharSequence, CharSequence) - */ - public static boolean equals(final CharSequence cs1, final CharSequence cs2) { - if (cs1 == cs2) { - return true; - } - if (cs1 == null || cs2 == null) { - return false; - } - if (cs1.length() != cs2.length()) { - return false; - } - if (cs1 instanceof String && cs2 instanceof String) { - return cs1.equals(cs2); - } - // Step-wise comparison - final int length = cs1.length(); - for (int i = 0; i < length; i++) { - if (cs1.charAt(i) != cs2.charAt(i)) { - return false; - } - } - return true; - } - - /** - *

- * Compares given {@code string} to a CharSequences vararg of - * {@code searchStrings}, returning {@code true} if the {@code string} is equal - * to any of the {@code searchStrings}. - *

- * - *
-	 * StringUtils.equalsAny(null, (CharSequence[]) null) = false
-	 * StringUtils.equalsAny(null, null, null)    = true
-	 * StringUtils.equalsAny(null, "abc", "def")  = false
-	 * StringUtils.equalsAny("abc", null, "def")  = false
-	 * StringUtils.equalsAny("abc", "abc", "def") = true
-	 * StringUtils.equalsAny("abc", "ABC", "DEF") = false
-	 * 
- * - * @param string to compare, may be {@code null}. - * @param searchStrings a vararg of strings, may be {@code null}. - * @return {@code true} if the string is equal (case-sensitive) to any other - * element of {@code searchStrings}; {@code false} if - * {@code searchStrings} is null or contains no matches. - * @since 3.5 - */ - public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) { - if (searchStrings.length > 0) { - for (final CharSequence next : searchStrings) { - if (equals(string, next)) { - return true; - } - } - } - return false; - } - - /** - *

- * Compares given {@code string} to a CharSequences vararg of - * {@code searchStrings}, returning {@code true} if the {@code string} is equal - * to any of the {@code searchStrings}, ignoring case. - *

- * - *
-	 * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
-	 * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
-	 * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
-	 * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
-	 * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
-	 * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
-	 * 
- * - * @param string to compare, may be {@code null}. - * @param searchStrings a vararg of strings, may be {@code null}. - * @return {@code true} if the string is equal (case-insensitive) to any other - * element of {@code searchStrings}; {@code false} if - * {@code searchStrings} is null or contains no matches. - * @since 3.5 - */ - public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) { - if (searchStrings.length > 0) { - for (final CharSequence next : searchStrings) { - if (equalsIgnoreCase(string, next)) { - return true; - } - } - } - return false; - } - - /** - *

- * Compares two CharSequences, returning {@code true} if they represent equal - * sequences of characters, ignoring case. - *

- * - *

- * {@code null}s are handled without exceptions. Two {@code null} references are - * considered equal. The comparison is case insensitive. - *

- * - *
-	 * StringUtils.equalsIgnoreCase(null, null)   = true
-	 * StringUtils.equalsIgnoreCase(null, "abc")  = false
-	 * StringUtils.equalsIgnoreCase("abc", null)  = false
-	 * StringUtils.equalsIgnoreCase("abc", "abc") = true
-	 * StringUtils.equalsIgnoreCase("abc", "ABC") = true
-	 * 
- * - * @param cs1 the first CharSequence, may be {@code null} - * @param cs2 the second CharSequence, may be {@code null} - * @return {@code true} if the CharSequences are equal (case-insensitive), or - * both {@code null} - * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to - * equalsIgnoreCase(CharSequence, CharSequence) - * @see #equals(CharSequence, CharSequence) - */ - public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) { - if (cs1 == cs2) { - return true; - } - if (cs1 == null || cs2 == null) { - return false; - } - if (cs1.length() != cs2.length()) { - return false; - } - return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length()); - } - - /** - *

- * Returns the first value in the array which is not empty (""), {@code null} or - * whitespace only. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *

- * If all values are blank or the array is {@code null} or empty then - * {@code null} is returned. - *

- * - *
-	 * StringUtils.firstNonBlank(null, null, null)     = null
-	 * StringUtils.firstNonBlank(null, "", " ")        = null
-	 * StringUtils.firstNonBlank("abc")                = "abc"
-	 * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
-	 * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
-	 * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
-	 * StringUtils.firstNonBlank()                     = null
-	 * 
- * - * @param the specific kind of CharSequence - * @param values the values to test, may be {@code null} or empty - * @return the first value from {@code values} which is not blank, or - * {@code null} if there are no non-blank values - * @since 3.8 - */ - @SafeVarargs - public static T firstNonBlank(final T... values) { - if (values != null) { - for (final T val : values) { - if (isNotBlank(val)) { - return val; - } - } - } - return null; - } - - /** - *

- * Returns the first value in the array which is not empty. - *

- * - *

- * If all values are empty or the array is {@code null} or empty then - * {@code null} is returned. - *

- * - *
-	 * StringUtils.firstNonEmpty(null, null, null)   = null
-	 * StringUtils.firstNonEmpty(null, null, "")     = null
-	 * StringUtils.firstNonEmpty(null, "", " ")      = " "
-	 * StringUtils.firstNonEmpty("abc")              = "abc"
-	 * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
-	 * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
-	 * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
-	 * StringUtils.firstNonEmpty()                   = null
-	 * 
- * - * @param the specific kind of CharSequence - * @param values the values to test, may be {@code null} or empty - * @return the first value from {@code values} which is not empty, or - * {@code null} if there are no non-empty values - * @since 3.8 - */ - @SafeVarargs - public static T firstNonEmpty(final T... values) { - if (values != null) { - for (final T val : values) { - if (isNotEmpty(val)) { - return val; - } - } - } - return null; - } - - /** - * Calls {@link String#getBytes(Charset)} in a null-safe manner. - * - * @param string input string - * @param charset The {@link Charset} to encode the {@code String}. If null, - * then use the default Charset. - * @return The empty byte[] if {@code string} is null, the result of - * {@link String#getBytes(Charset)} otherwise. - * @see String#getBytes(Charset) - * @since 3.10 - */ - public static byte[] getBytes(final String string, final Charset charset) { - return string == null ? new byte[0] : string.getBytes(Charsets.toCharset(charset)); - } - - /** - * Calls {@link String#getBytes(String)} in a null-safe manner. - * - * @param string input string - * @param charset The {@link Charset} name to encode the {@code String}. If - * null, then use the default Charset. - * @return The empty byte[] if {@code string} is null, the result of - * {@link String#getBytes(String)} otherwise. - * @throws UnsupportedEncodingException Thrown when the named charset is not - * supported. - * @see String#getBytes(String) - * @since 3.10 - */ - public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException { - return string == null ? new byte[0] : string.getBytes(Charsets.toCharsetName(charset)); - } - - /** - *

- * Compares all Strings in an array and returns the initial sequence of - * characters that is common to all of them. - *

- * - *

- * For example, {@code getCommonPrefix(new String[] {"i am a machine", "i am a - * robot"}) -> "i am a "} - *

- * - *
-	 * StringUtils.getCommonPrefix(null) = ""
-	 * StringUtils.getCommonPrefix(new String[] {}) = ""
-	 * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
-	 * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
-	 * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
-	 * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
-	 * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
-	 * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
-	 * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
-	 * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
-	 * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
-	 * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
-	 * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
-	 * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
-	 * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
-	 * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
-	 * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
-	 * 
- * - * @param strs array of String objects, entries may be null - * @return the initial sequence of characters that are common to all Strings in - * the array; empty String if the array is null, the elements are all - * null or if there is no common prefix. - * @since 2.4 - */ - public static String getCommonPrefix(final String... strs) { - if (strs.length == 0) { - return EMPTY; - } - final int smallestIndexOfDiff = indexOfDifference(strs); - if (smallestIndexOfDiff == INDEX_NOT_FOUND) { - // all strings were identical - if (strs[0] == null) { - return EMPTY; - } - return strs[0]; - } else if (smallestIndexOfDiff == 0) { - // there were no common initial characters - return EMPTY; - } else { - // we found a common initial character sequence - return strs[0].substring(0, smallestIndexOfDiff); - } - } - - /** - *

- * Checks if a String {@code str} contains Unicode digits, if yes then - * concatenate all the digits in {@code str} and return it as a String. - *

- * - *

- * An empty ("") String will be returned if no digits found in {@code str}. - *

- * - *
-	 * StringUtils.getDigits(null)  = null
-	 * StringUtils.getDigits("")    = ""
-	 * StringUtils.getDigits("abc") = ""
-	 * StringUtils.getDigits("1000$") = "1000"
-	 * StringUtils.getDigits("1123~45") = "112345"
-	 * StringUtils.getDigits("(541) 754-3010") = "5417543010"
-	 * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
-	 * 
- * - * @param str the String to extract digits from, may be null - * @return String with only digits, or an empty ("") String if no digits found, - * or {@code null} String if {@code str} is null - * @since 3.6 - */ - public static String getDigits(final String str) { - if (isEmpty(str)) { - return str; - } - final int sz = str.length(); - final StringBuilder strDigits = new StringBuilder(sz); - for (int i = 0; i < sz; i++) { - final char tempChar = str.charAt(i); - if (Character.isDigit(tempChar)) { - strDigits.append(tempChar); - } - } - return strDigits.toString(); - } - - /** - *

- * Find the Fuzzy Distance which indicates the similarity score between two - * Strings. - *

- * - *

- * This string matching algorithm is similar to the algorithms of editors such - * as Sublime Text, TextMate, Atom and others. One point is given for every - * matched character. Subsequent matches yield two bonus points. A higher score - * indicates a higher similarity. - *

- * - *
-	 * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
-	 * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
-	 * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
-	 * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
-	 * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
-	 * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
-	 * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
-	 * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
-	 * 
- * - * @param term a full term that should be matched against, must not be null - * @param query the query that will be matched against a term, must not be null - * @param locale This string matching logic is case insensitive. A locale is - * necessary to normalize both Strings to lower case. - * @return result score - * @throws IllegalArgumentException if either String input {@code null} or - * Locale input {@code null} - * @since 3.4 - * @deprecated as of 3.6, use commons-text - * FuzzyScore instead - */ - @Deprecated - public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) { - if (term == null || query == null) { - throw new IllegalArgumentException("Strings must not be null"); - } else if (locale == null) { - throw new IllegalArgumentException("Locale must not be null"); - } - - // fuzzy logic is case insensitive. We normalize the Strings to lower - // case right from the start. Turning characters to lower case - // via Character.toLowerCase(char) is unfortunately insufficient - // as it does not accept a locale. - final String termLowerCase = term.toString().toLowerCase(locale); - final String queryLowerCase = query.toString().toLowerCase(locale); - - // the resulting score - int score = 0; - - // the position in the term which will be scanned next for potential - // query character matches - int termIndex = 0; - - // index of the previously matched character in the term - int previousMatchingCharacterIndex = Integer.MIN_VALUE; - - for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) { - final char queryChar = queryLowerCase.charAt(queryIndex); - - boolean termCharacterMatchFound = false; - for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) { - final char termChar = termLowerCase.charAt(termIndex); - - if (queryChar == termChar) { - // simple character matches result in one point - score++; - - // subsequent character matches further improve - // the score. - if (previousMatchingCharacterIndex + 1 == termIndex) { - score += 2; - } - - previousMatchingCharacterIndex = termIndex; - - // we can leave the nested loop. Every character in the - // query can match at most one character in the term. - termCharacterMatchFound = true; - } - } - } - - return score; - } - - /** - *

- * Returns either the passed in CharSequence, or if the CharSequence is - * whitespace, empty ("") or {@code null}, the value supplied by - * {@code defaultStrSupplier}. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *

- * Caller responsible for thread-safety and exception handling of default value - * supplier - *

- * - *
-	 * {@code
-	 * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
-	 * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
-	 * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
-	 * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
-	 * StringUtils.getIfBlank("", () -> null)       = null
-	 * StringUtils.getIfBlank("", null)             = null
-	 * }
-	 * 
- * - * @param the specific kind of CharSequence - * @param str the CharSequence to check, may be null - * @param defaultSupplier the supplier of default CharSequence to return if the - * input is whitespace, empty ("") or {@code null}, may - * be null - * @return the passed in CharSequence, or the default - * @see StringUtils#defaultString(String, String) - * @since 3.10 - */ - public static T getIfBlank(final T str, final Supplier defaultSupplier) { - return isBlank(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str; - } - - /** - *

- * Returns either the passed in CharSequence, or if the CharSequence is empty or - * {@code null}, the value supplied by {@code defaultStrSupplier}. - *

- * - *

- * Caller responsible for thread-safety and exception handling of default value - * supplier - *

- * - *
-	 * {@code
-	 * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
-	 * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
-	 * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
-	 * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
-	 * StringUtils.getIfEmpty("", () -> null)        = null
-	 * StringUtils.getIfEmpty("", null)              = null
-	 * }
-	 * 
- * - * @param the specific kind of CharSequence - * @param str the CharSequence to check, may be null - * @param defaultSupplier the supplier of default CharSequence to return if the - * input is empty ("") or {@code null}, may be null - * @return the passed in CharSequence, or the default - * @see StringUtils#defaultString(String, String) - * @since 3.10 - */ - public static T getIfEmpty(final T str, final Supplier defaultSupplier) { - return isEmpty(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str; - } - - /** - *

- * Find the Jaro Winkler Distance which indicates the similarity score between - * two Strings. - *

- * - *

- * The Jaro measure is the weighted sum of percentage of matched characters from - * each file and transposed characters. Winkler increased this measure for - * matching initial characters. - *

- * - *

- * This implementation is based on the Jaro Winkler similarity algorithm from - * http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance. - *

- * - *
-	 * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
-	 * StringUtils.getJaroWinklerDistance("", "")              = 0.0
-	 * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
-	 * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
-	 * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
-	 * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
-	 * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
-	 * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
-	 * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
-	 * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
-	 * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
-	 * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D & H Enterprises, Inc.") = 0.95
-	 * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
-	 * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
-	 * 
- * - * @param first the first String, must not be null - * @param second the second String, must not be null - * @return result distance - * @throws IllegalArgumentException if either String input {@code null} - * @since 3.3 - * @deprecated as of 3.6, use commons-text - * JaroWinklerDistance instead - */ - @Deprecated - public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) { - final double DEFAULT_SCALING_FACTOR = 0.1; - - if (first == null || second == null) { - throw new IllegalArgumentException("Strings must not be null"); - } - - final int[] mtp = matches(first, second); - final double m = mtp[0]; - if (m == 0) { - return 0D; - } - final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3; - final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j); - return Math.round(jw * 100.0D) / 100.0D; - } - - /** - *

- * Find the Levenshtein distance between two Strings. - *

- * - *

- * This is the number of changes needed to change one String into another, where - * each change is a single character modification (deletion, insertion or - * substitution). - *

- * - *

- * The implementation uses a single-dimensional array of length s.length() + 1. - * See - * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html - * for details. - *

- * - *
-	 * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
-	 * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
-	 * StringUtils.getLevenshteinDistance("", "")              = 0
-	 * StringUtils.getLevenshteinDistance("", "a")             = 1
-	 * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
-	 * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
-	 * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
-	 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
-	 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
-	 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
-	 * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
-	 * 
- * - * @param s the first String, must not be null - * @param t the second String, must not be null - * @return result distance - * @throws IllegalArgumentException if either String input {@code null} - * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to - * getLevenshteinDistance(CharSequence, CharSequence) - * @deprecated as of 3.6, use commons-text - * LevenshteinDistance instead - */ - @Deprecated - public static int getLevenshteinDistance(CharSequence s, CharSequence t) { - if (s == null || t == null) { - throw new IllegalArgumentException("Strings must not be null"); - } - - int n = s.length(); - int m = t.length(); - - if (n == 0) { - return m; - } else if (m == 0) { - return n; - } - - if (n > m) { - // swap the input strings to consume less memory - final CharSequence tmp = s; - s = t; - t = tmp; - n = m; - m = t.length(); - } - - final int[] p = new int[n + 1]; - // indexes into strings s and t - int i; // iterates through s - int j; // iterates through t - int upper_left; - int upper; - - char t_j; // jth character of t - int cost; - - for (i = 0; i <= n; i++) { - p[i] = i; - } - - for (j = 1; j <= m; j++) { - upper_left = p[0]; - t_j = t.charAt(j - 1); - p[0] = j; - - for (i = 1; i <= n; i++) { - upper = p[i]; - cost = s.charAt(i - 1) == t_j ? 0 : 1; - // minimum of cell to the left+1, to the top+1, diagonally left and up +cost - p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost); - upper_left = upper; - } - } - - return p[n]; - } - - /** - *

- * Find the Levenshtein distance between two Strings if it's less than or equal - * to a given threshold. - *

- * - *

- * This is the number of changes needed to change one String into another, where - * each change is a single character modification (deletion, insertion or - * substitution). - *

- * - *

- * This implementation follows from Algorithms on Strings, Trees and Sequences - * by Dan Gusfield and Chas Emerick's implementation of the Levenshtein distance - * algorithm from http://www.merriampark.com/ld.htm - *

- * - *
-	 * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
-	 * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
-	 * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
-	 * StringUtils.getLevenshteinDistance("", "", 0)              = 0
-	 * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
-	 * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
-	 * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
-	 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
-	 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
-	 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
-	 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
-	 * 
- * - * @param s the first String, must not be null - * @param t the second String, must not be null - * @param threshold the target threshold, must not be negative - * @return result distance, or {@code -1} if the distance would be greater than - * the threshold - * @throws IllegalArgumentException if either String input {@code null} or - * negative threshold - * @deprecated as of 3.6, use commons-text - * LevenshteinDistance instead - */ - @Deprecated - public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) { - if (s == null || t == null) { - throw new IllegalArgumentException("Strings must not be null"); - } - if (threshold < 0) { - throw new IllegalArgumentException("Threshold must not be negative"); - } - - /* - * This implementation only computes the distance if it's less than or equal to - * the threshold value, returning -1 if it's greater. The advantage is - * performance: unbounded distance is O(nm), but a bound of k allows us to - * reduce it to O(km) time by only computing a diagonal stripe of width 2k + 1 - * of the cost table. It is also possible to use this to compute the unbounded - * Levenshtein distance by starting the threshold at 1 and doubling each time - * until the distance is found; this is O(dm), where d is the distance. - * - * One subtlety comes from needing to ignore entries on the border of our stripe - * eg. p[] = |#|#|#|* d[] = *|#|#|#| We must ignore the entry to the left of the - * leftmost member We must ignore the entry above the rightmost member - * - * Another subtlety comes from our stripe running off the matrix if the strings - * aren't of the same size. Since string s is always swapped to be the shorter - * of the two, the stripe will always run off to the upper right instead of the - * lower left of the matrix. - * - * As a concrete example, suppose s is of length 5, t is of length 7, and our - * threshold is 1. In this case we're going to walk a stripe of length 3. The - * matrix would look like so: - * - * 1 2 3 4 5 1 |#|#| | | | 2 |#|#|#| | | 3 | |#|#|#| | 4 | | |#|#|#| 5 | | | - * |#|#| 6 | | | | |#| 7 | | | | | | - * - * Note how the stripe leads off the table as there is no possible way to turn a - * string of length 5 into one of length 7 in edit distance of 1. - * - * Additionally, this implementation decreases memory usage by using two - * single-dimensional arrays and swapping them back and forth instead of - * allocating an entire n by m matrix. This requires a few minor changes, such - * as immediately returning when it's detected that the stripe has run off the - * matrix and initially filling the arrays with large values so that entries we - * don't compute are ignored. - * - * See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some - * discussion. - */ - - int n = s.length(); // length of s - int m = t.length(); // length of t - - // if one string is empty, the edit distance is necessarily the length of the - // other - if (n == 0) { - return m <= threshold ? m : -1; - } else if (m == 0) { - return n <= threshold ? n : -1; - } else if (Math.abs(n - m) > threshold) { - // no need to calculate the distance if the length difference is greater than - // the threshold - return -1; - } - - if (n > m) { - // swap the two strings to consume less memory - final CharSequence tmp = s; - s = t; - t = tmp; - n = m; - m = t.length(); - } - - int[] p = new int[n + 1]; // 'previous' cost array, horizontally - int[] d = new int[n + 1]; // cost array, horizontally - int[] _d; // placeholder to assist in swapping p and d - - // fill in starting table values - final int boundary = Math.min(n, threshold) + 1; - for (int i = 0; i < boundary; i++) { - p[i] = i; - } - // these fills ensure that the value above the rightmost entry of our - // stripe will be ignored in following loop iterations - Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); - Arrays.fill(d, Integer.MAX_VALUE); - - // iterates through t - for (int j = 1; j <= m; j++) { - final char t_j = t.charAt(j - 1); // jth character of t - d[0] = j; - - // compute stripe indices, constrain to array size - final int min = Math.max(1, j - threshold); - final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold); - - // the stripe may lead off of the table if s and t are of different sizes - if (min > max) { - return -1; - } - - // ignore entry left of leftmost - if (min > 1) { - d[min - 1] = Integer.MAX_VALUE; - } - - // iterates through [min, max] in s - for (int i = min; i <= max; i++) { - if (s.charAt(i - 1) == t_j) { - // diagonally left and up - d[i] = p[i - 1]; - } else { - // 1 + minimum of cell to the left, to the top, diagonally left and up - d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); - } - } - - // copy current distance counts to 'previous row' distance counts - _d = p; - p = d; - d = _d; - } - - // if p[n] is greater than the threshold, there's no guarantee on it being the - // correct - // distance - if (p[n] <= threshold) { - return p[n]; - } - return -1; - } - - /** - *

- * Finds the first index within a CharSequence, handling {@code null}. This - * method uses {@link String#indexOf(String, int)} if possible. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. - *

- * - *
-	 * StringUtils.indexOf(null, *)          = -1
-	 * StringUtils.indexOf(*, null)          = -1
-	 * StringUtils.indexOf("", "")           = 0
-	 * StringUtils.indexOf("", *)            = -1 (except when * = "")
-	 * StringUtils.indexOf("aabaabaa", "a")  = 0
-	 * StringUtils.indexOf("aabaabaa", "b")  = 2
-	 * StringUtils.indexOf("aabaabaa", "ab") = 1
-	 * StringUtils.indexOf("aabaabaa", "")   = 0
-	 * 
- * - * @param seq the CharSequence to check, may be null - * @param searchSeq the CharSequence to find, may be null - * @return the first index of the search CharSequence, -1 if no match or - * {@code null} string input - * @since 2.0 - * @since 3.0 Changed signature from indexOf(String, String) to - * indexOf(CharSequence, CharSequence) - */ - public static int indexOf(final CharSequence seq, final CharSequence searchSeq) { - if (seq == null || searchSeq == null) { - return INDEX_NOT_FOUND; - } - return CharSequenceUtils.indexOf(seq, searchSeq, 0); - } - - /** - *

- * Finds the first index within a CharSequence, handling {@code null}. This - * method uses {@link String#indexOf(String, int)} if possible. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. A negative start position - * is treated as zero. An empty ("") search CharSequence always matches. A start - * position greater than the string length only matches an empty search - * CharSequence. - *

- * - *
-	 * StringUtils.indexOf(null, *, *)          = -1
-	 * StringUtils.indexOf(*, null, *)          = -1
-	 * StringUtils.indexOf("", "", 0)           = 0
-	 * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
-	 * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
-	 * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
-	 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
-	 * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
-	 * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
-	 * StringUtils.indexOf("aabaabaa", "b", -1) = 2
-	 * StringUtils.indexOf("aabaabaa", "", 2)   = 2
-	 * StringUtils.indexOf("abc", "", 9)        = 3
-	 * 
- * - * @param seq the CharSequence to check, may be null - * @param searchSeq the CharSequence to find, may be null - * @param startPos the start position, negative treated as zero - * @return the first index of the search CharSequence (always ≥ startPos), -1 - * if no match or {@code null} string input - * @since 2.0 - * @since 3.0 Changed signature from indexOf(String, String, int) to - * indexOf(CharSequence, CharSequence, int) - */ - public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { - if (seq == null || searchSeq == null) { - return INDEX_NOT_FOUND; - } - return CharSequenceUtils.indexOf(seq, searchSeq, startPos); - } - - /** - * Returns the index within {@code seq} of the first occurrence of the specified - * character. If a character with value {@code searchChar} occurs in the - * character sequence represented by {@code seq} {@code CharSequence} object, - * then the index (in Unicode code units) of the first such occurrence is - * returned. For values of {@code searchChar} in the range from 0 to 0xFFFF - * (inclusive), this is the smallest value k such that:
- * - *
-	 * this.charAt(k) == searchChar
-	 * 
- * - *
is true. For other values of {@code searchChar}, it is the - * smallest value k such that:
- * - *
-	 * this.codePointAt(k) == searchChar
-	 * 
- * - *
is true. In either case, if no such character occurs in - * {@code seq}, then {@code INDEX_NOT_FOUND (-1)} is returned. - * - *

- * Furthermore, a {@code null} or empty ("") CharSequence will return - * {@code INDEX_NOT_FOUND (-1)}. - *

- * - *
-	 * StringUtils.indexOf(null, *)         = -1
-	 * StringUtils.indexOf("", *)           = -1
-	 * StringUtils.indexOf("aabaabaa", 'a') = 0
-	 * StringUtils.indexOf("aabaabaa", 'b') = 2
-	 * 
- * - * @param seq the CharSequence to check, may be null - * @param searchChar the character to find - * @return the first index of the search character, -1 if no match or - * {@code null} string input - * @since 2.0 - * @since 3.0 Changed signature from indexOf(String, int) to - * indexOf(CharSequence, int) - * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like - * {@code String} - */ - public static int indexOf(final CharSequence seq, final int searchChar) { - if (isEmpty(seq)) { - return INDEX_NOT_FOUND; - } - return CharSequenceUtils.indexOf(seq, searchChar, 0); - } - - /** - * - * Returns the index within {@code seq} of the first occurrence of the specified - * character, starting the search at the specified index. - *

- * If a character with value {@code searchChar} occurs in the character sequence - * represented by the {@code seq} {@code CharSequence} object at an index no - * smaller than {@code startPos}, then the index of the first such occurrence is - * returned. For values of {@code searchChar} in the range from 0 to 0xFFFF - * (inclusive), this is the smallest value k such that:

- * - *
-	 * (this.charAt(k) == searchChar) && (k >= startPos)
-	 * 
- * - *
is true. For other values of {@code searchChar}, it is the - * smallest value k such that:
- * - *
-	 * (this.codePointAt(k) == searchChar) && (k >= startPos)
-	 * 
- * - *
is true. In either case, if no such character occurs in - * {@code seq} at or after position {@code startPos}, then {@code -1} is - * returned. - * - *

- * There is no restriction on the value of {@code startPos}. If it is negative, - * it has the same effect as if it were zero: this entire string may be - * searched. If it is greater than the length of this string, it has the same - * effect as if it were equal to the length of this string: - * {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a {@code null} or - * empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}. - * - *

- * All indices are specified in {@code char} values (Unicode code units). - * - *

-	 * StringUtils.indexOf(null, *, *)          = -1
-	 * StringUtils.indexOf("", *, *)            = -1
-	 * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
-	 * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
-	 * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
-	 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
-	 * 
- * - * @param seq the CharSequence to check, may be null - * @param searchChar the character to find - * @param startPos the start position, negative treated as zero - * @return the first index of the search character (always ≥ startPos), -1 if - * no match or {@code null} string input - * @since 2.0 - * @since 3.0 Changed signature from indexOf(String, int, int) to - * indexOf(CharSequence, int, int) - * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like - * {@code String} - */ - public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) { - if (isEmpty(seq)) { - return INDEX_NOT_FOUND; - } - return CharSequenceUtils.indexOf(seq, searchChar, startPos); - } - - /** - *

- * Search a CharSequence to find the first index of any character in the given - * set of characters. - *

- * - *

- * A {@code null} String will return {@code -1}. A {@code null} or zero length - * search array will return {@code -1}. - *

- * - *
-	 * StringUtils.indexOfAny(null, *)                  = -1
-	 * StringUtils.indexOfAny("", *)                    = -1
-	 * StringUtils.indexOfAny(*, null)                  = -1
-	 * StringUtils.indexOfAny(*, [])                    = -1
-	 * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
-	 * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
-	 * StringUtils.indexOfAny("aba", ['z'])             = -1
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @param searchChars the chars to search for, may be null - * @return the index of any of the chars, -1 if no match or null input - * @since 2.0 - * @since 3.0 Changed signature from indexOfAny(String, char[]) to - * indexOfAny(CharSequence, char...) - */ - public static int indexOfAny(final CharSequence cs, final char... searchChars) { - if (isEmpty(cs) || searchChars.length == 0) { - return INDEX_NOT_FOUND; - } - final int csLen = cs.length(); - final int csLast = csLen - 1; - final int searchLen = searchChars.length; - final int searchLast = searchLen - 1; - for (int i = 0; i < csLen; i++) { - final char ch = cs.charAt(i); - for (int j = 0; j < searchLen; j++) { - if (searchChars[j] == ch) { - if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { - // ch is a supplementary character - if (searchChars[j + 1] == cs.charAt(i + 1)) { - return i; - } - } else { - return i; - } - } - } - } - return INDEX_NOT_FOUND; - } - - /** - *

- * Find the first index of any of a set of potential substrings. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. A {@code null} or zero - * length search array will return {@code -1}. A {@code null} search array entry - * will be ignored, but a search array containing "" will return {@code 0} if - * {@code str} is not null. This method uses {@link String#indexOf(String)} if - * possible. - *

- * - *
-	 * StringUtils.indexOfAny(null, *)                      = -1
-	 * StringUtils.indexOfAny(*, null)                      = -1
-	 * StringUtils.indexOfAny(*, [])                        = -1
-	 * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
-	 * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
-	 * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
-	 * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
-	 * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
-	 * StringUtils.indexOfAny("", [""])                     = 0
-	 * StringUtils.indexOfAny("", ["a"])                    = -1
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param searchStrs the CharSequences to search for, may be null - * @return the first index of any of the searchStrs in str, -1 if no match - * @since 3.0 Changed signature from indexOfAny(String, String[]) to - * indexOfAny(CharSequence, CharSequence...) - */ - public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) { - if (str == null || searchStrs == null) { - return INDEX_NOT_FOUND; - } - - // String's can't have a MAX_VALUEth index. - int ret = Integer.MAX_VALUE; - - int tmp = 0; - for (final CharSequence search : searchStrs) { - if (search == null) { - continue; - } - tmp = CharSequenceUtils.indexOf(str, search, 0); - if (tmp == INDEX_NOT_FOUND) { - continue; - } - - if (tmp < ret) { - ret = tmp; - } - } - - return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret; - } - - /** - *

- * Search a CharSequence to find the first index of any character in the given - * set of characters. - *

- * - *

- * A {@code null} String will return {@code -1}. A {@code null} search string - * will return {@code -1}. - *

- * - *
-	 * StringUtils.indexOfAny(null, *)            = -1
-	 * StringUtils.indexOfAny("", *)              = -1
-	 * StringUtils.indexOfAny(*, null)            = -1
-	 * StringUtils.indexOfAny(*, "")              = -1
-	 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
-	 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
-	 * StringUtils.indexOfAny("aba", "z")         = -1
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @param searchChars the chars to search for, may be null - * @return the index of any of the chars, -1 if no match or null input - * @since 2.0 - * @since 3.0 Changed signature from indexOfAny(String, String) to - * indexOfAny(CharSequence, String) - */ - public static int indexOfAny(final CharSequence cs, final String searchChars) { - if (isEmpty(cs) || isEmpty(searchChars)) { - return INDEX_NOT_FOUND; - } - return indexOfAny(cs, searchChars.toCharArray()); - } - - /** - *

- * Searches a CharSequence to find the first index of any character not in the - * given set of characters. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. A {@code null} or zero - * length search array will return {@code -1}. - *

- * - *
-	 * StringUtils.indexOfAnyBut(null, *)                              = -1
-	 * StringUtils.indexOfAnyBut("", *)                                = -1
-	 * StringUtils.indexOfAnyBut(*, null)                              = -1
-	 * StringUtils.indexOfAnyBut(*, [])                                = -1
-	 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
-	 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
-	 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
-	 * 
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @param searchChars the chars to search for, may be null - * @return the index of any of the chars, -1 if no match or null input - * @since 2.0 - * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to - * indexOfAnyBut(CharSequence, char...) - */ - public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) { - if (isEmpty(cs) || searchChars.length == 0) { - return INDEX_NOT_FOUND; - } - final int csLen = cs.length(); - final int csLast = csLen - 1; - final int searchLen = searchChars.length; - final int searchLast = searchLen - 1; - outer: for (int i = 0; i < csLen; i++) { - final char ch = cs.charAt(i); - for (int j = 0; j < searchLen; j++) { - if (searchChars[j] == ch) { - if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { - if (searchChars[j + 1] == cs.charAt(i + 1)) { - continue outer; - } - } else { - continue outer; - } - } - } - return i; - } - return INDEX_NOT_FOUND; - } - - /** - *

- * Search a CharSequence to find the first index of any character not in the - * given set of characters. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. A {@code null} or empty - * search string will return {@code -1}. - *

- * - *
-	 * StringUtils.indexOfAnyBut(null, *)            = -1
-	 * StringUtils.indexOfAnyBut("", *)              = -1
-	 * StringUtils.indexOfAnyBut(*, null)            = -1
-	 * StringUtils.indexOfAnyBut(*, "")              = -1
-	 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
-	 * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
-	 * StringUtils.indexOfAnyBut("aba", "ab")        = -1
-	 * 
- * - * @param seq the CharSequence to check, may be null - * @param searchChars the chars to search for, may be null - * @return the index of any of the chars, -1 if no match or null input - * @since 2.0 - * @since 3.0 Changed signature from indexOfAnyBut(String, String) to - * indexOfAnyBut(CharSequence, CharSequence) - */ - public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) { - if (isEmpty(seq) || isEmpty(searchChars)) { - return INDEX_NOT_FOUND; - } - final int strLen = seq.length(); - for (int i = 0; i < strLen; i++) { - final char ch = seq.charAt(i); - final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0; - if (i + 1 < strLen && Character.isHighSurrogate(ch)) { - final char ch2 = seq.charAt(i + 1); - if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) { - return i; - } - } else if (!chFound) { - return i; - } - } - return INDEX_NOT_FOUND; - } - - /** - *

- * Compares all CharSequences in an array and returns the index at which the - * CharSequences begin to differ. - *

- * - *

- * For example, {@code indexOfDifference(new String[] {"i am a machine", "i am a - * robot"}) -> 7} - *

- * - *
-	 * StringUtils.indexOfDifference(null) = -1
-	 * StringUtils.indexOfDifference(new String[] {}) = -1
-	 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
-	 * StringUtils.indexOfDifference(new String[] {null, null}) = -1
-	 * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
-	 * StringUtils.indexOfDifference(new String[] {"", null}) = 0
-	 * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
-	 * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
-	 * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
-	 * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
-	 * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
-	 * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
-	 * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
-	 * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
-	 * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
-	 * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
-	 * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
-	 * 
- * - * @param css array of CharSequences, entries may be null - * @return the index where the strings begin to differ; -1 if they are all equal - * @since 2.4 - * @since 3.0 Changed signature from indexOfDifference(String...) to - * indexOfDifference(CharSequence...) - */ - public static int indexOfDifference(final CharSequence... css) { - if (css.length <= 1) { - return INDEX_NOT_FOUND; - } - boolean anyStringNull = false; - boolean allStringsNull = true; - final int arrayLen = css.length; - int shortestStrLen = Integer.MAX_VALUE; - int longestStrLen = 0; - - // find the min and max string lengths; this avoids checking to make - // sure we are not exceeding the length of the string each time through - // the bottom loop. - for (final CharSequence cs : css) { - if (cs == null) { - anyStringNull = true; - shortestStrLen = 0; - } else { - allStringsNull = false; - shortestStrLen = Math.min(cs.length(), shortestStrLen); - longestStrLen = Math.max(cs.length(), longestStrLen); - } - } - - // handle lists containing all nulls or all empty strings - if (allStringsNull || longestStrLen == 0 && !anyStringNull) { - return INDEX_NOT_FOUND; - } - - // handle lists containing some nulls or some empty strings - if (shortestStrLen == 0) { - return 0; - } - - // find the position with the first difference across all strings - int firstDiff = -1; - for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) { - final char comparisonChar = css[0].charAt(stringPos); - for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) { - if (css[arrayPos].charAt(stringPos) != comparisonChar) { - firstDiff = stringPos; - break; - } - } - if (firstDiff != -1) { - break; - } - } - - if (firstDiff == -1 && shortestStrLen != longestStrLen) { - // we compared all of the characters up to the length of the - // shortest string and didn't find a match, but the string lengths - // vary, so return the length of the shortest string. - return shortestStrLen; - } - return firstDiff; - } - - /** - *

- * Compares two CharSequences, and returns the index at which the CharSequences - * begin to differ. - *

- * - *

- * For example, {@code indexOfDifference("i am a machine", "i am a robot") -> 7} - *

- * - *
-	 * StringUtils.indexOfDifference(null, null) = -1
-	 * StringUtils.indexOfDifference("", "") = -1
-	 * StringUtils.indexOfDifference("", "abc") = 0
-	 * StringUtils.indexOfDifference("abc", "") = 0
-	 * StringUtils.indexOfDifference("abc", "abc") = -1
-	 * StringUtils.indexOfDifference("ab", "abxyz") = 2
-	 * StringUtils.indexOfDifference("abcde", "abxyz") = 2
-	 * StringUtils.indexOfDifference("abcde", "xyz") = 0
-	 * 
- * - * @param cs1 the first CharSequence, may be null - * @param cs2 the second CharSequence, may be null - * @return the index where cs1 and cs2 begin to differ; -1 if they are equal - * @since 2.0 - * @since 3.0 Changed signature from indexOfDifference(String, String) to - * indexOfDifference(CharSequence, CharSequence) - */ - public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { - if (cs1 == cs2) { - return INDEX_NOT_FOUND; - } - if (cs1 == null || cs2 == null) { - return 0; - } - int i; - for (i = 0; i < cs1.length() && i < cs2.length(); ++i) { - if (cs1.charAt(i) != cs2.charAt(i)) { - break; - } - } - if (i < cs2.length() || i < cs1.length()) { - return i; - } - return INDEX_NOT_FOUND; - } - - /** - *

- * Case in-sensitive find of the first index within a CharSequence. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. A negative start position - * is treated as zero. An empty ("") search CharSequence always matches. A start - * position greater than the string length only matches an empty search - * CharSequence. - *

- * - *
-	 * StringUtils.indexOfIgnoreCase(null, *)          = -1
-	 * StringUtils.indexOfIgnoreCase(*, null)          = -1
-	 * StringUtils.indexOfIgnoreCase("", "")           = 0
-	 * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
-	 * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
-	 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @return the first index of the search CharSequence, -1 if no match or - * {@code null} string input - * @since 2.5 - * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to - * indexOfIgnoreCase(CharSequence, CharSequence) - */ - public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { - return indexOfIgnoreCase(str, searchStr, 0); - } - - /** - *

- * Case in-sensitive find of the first index within a CharSequence from the - * specified position. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. A negative start position - * is treated as zero. An empty ("") search CharSequence always matches. A start - * position greater than the string length only matches an empty search - * CharSequence. - *

- * - *
-	 * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
-	 * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
-	 * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
-	 * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
-	 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
-	 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
-	 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
-	 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
-	 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
-	 * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
-	 * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @param startPos the start position, negative treated as zero - * @return the first index of the search CharSequence (always ≥ startPos), -1 - * if no match or {@code null} string input - * @since 2.5 - * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to - * indexOfIgnoreCase(CharSequence, CharSequence, int) - */ - public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { - if (str == null || searchStr == null) { - return INDEX_NOT_FOUND; - } - if (startPos < 0) { - startPos = 0; - } - final int endLimit = str.length() - searchStr.length() + 1; - if (startPos > endLimit) { - return INDEX_NOT_FOUND; - } - if (searchStr.length() == 0) { - return startPos; - } - for (int i = startPos; i < endLimit; i++) { - if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { - return i; - } - } - return INDEX_NOT_FOUND; - } - - /** - *

- * Checks if all of the CharSequences are empty (""), null or whitespace only. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.isAllBlank(null)             = true
-	 * StringUtils.isAllBlank(null, "foo")      = false
-	 * StringUtils.isAllBlank(null, null)       = true
-	 * StringUtils.isAllBlank("", "bar")        = false
-	 * StringUtils.isAllBlank("bob", "")        = false
-	 * StringUtils.isAllBlank("  bob  ", null)  = false
-	 * StringUtils.isAllBlank(" ", "bar")       = false
-	 * StringUtils.isAllBlank("foo", "bar")     = false
-	 * StringUtils.isAllBlank(new String[] {})  = true
-	 * 
- * - * @param css the CharSequences to check, may be null or empty - * @return {@code true} if all of the CharSequences are empty or null or - * whitespace only - * @since 3.6 - */ - public static boolean isAllBlank(final CharSequence... css) { - if (css.length == 0) { - return true; - } - for (final CharSequence cs : css) { - if (isNotBlank(cs)) { - return false; - } - } - return true; - } - - /** - *

- * Checks if all of the CharSequences are empty ("") or null. - *

- * - *
-	 * StringUtils.isAllEmpty(null)             = true
-	 * StringUtils.isAllEmpty(null, "")         = true
-	 * StringUtils.isAllEmpty(new String[] {})  = true
-	 * StringUtils.isAllEmpty(null, "foo")      = false
-	 * StringUtils.isAllEmpty("", "bar")        = false
-	 * StringUtils.isAllEmpty("bob", "")        = false
-	 * StringUtils.isAllEmpty("  bob  ", null)  = false
-	 * StringUtils.isAllEmpty(" ", "bar")       = false
-	 * StringUtils.isAllEmpty("foo", "bar")     = false
-	 * 
- * - * @param css the CharSequences to check, may be null or empty - * @return {@code true} if all of the CharSequences are empty or null - * @since 3.6 - */ - public static boolean isAllEmpty(final CharSequence... css) { - if (css.length == 0) { - return true; - } - for (final CharSequence cs : css) { - if (isNotEmpty(cs)) { - return false; - } - } - return true; - } - - /** - *

- * Checks if the CharSequence contains only lowercase characters. - *

- * - *

- * {@code null} will return {@code false}. An empty CharSequence (length()=0) - * will return {@code false}. - *

- * - *
-	 * StringUtils.isAllLowerCase(null)   = false
-	 * StringUtils.isAllLowerCase("")     = false
-	 * StringUtils.isAllLowerCase("  ")   = false
-	 * StringUtils.isAllLowerCase("abc")  = true
-	 * StringUtils.isAllLowerCase("abC")  = false
-	 * StringUtils.isAllLowerCase("ab c") = false
-	 * StringUtils.isAllLowerCase("ab1c") = false
-	 * StringUtils.isAllLowerCase("ab/c") = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if only contains lowercase characters, and is non-null - * @since 2.5 - * @since 3.0 Changed signature from isAllLowerCase(String) to - * isAllLowerCase(CharSequence) - */ - public static boolean isAllLowerCase(final CharSequence cs) { - if (isEmpty(cs)) { - return false; - } - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - if (!Character.isLowerCase(cs.charAt(i))) { - return false; - } - } - return true; - } - - /** - *

- * Checks if the CharSequence contains only uppercase characters. - *

- * - *

- * {@code null} will return {@code false}. An empty String (length()=0) will - * return {@code false}. - *

- * - *
-	 * StringUtils.isAllUpperCase(null)   = false
-	 * StringUtils.isAllUpperCase("")     = false
-	 * StringUtils.isAllUpperCase("  ")   = false
-	 * StringUtils.isAllUpperCase("ABC")  = true
-	 * StringUtils.isAllUpperCase("aBC")  = false
-	 * StringUtils.isAllUpperCase("A C")  = false
-	 * StringUtils.isAllUpperCase("A1C")  = false
-	 * StringUtils.isAllUpperCase("A/C")  = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if only contains uppercase characters, and is non-null - * @since 2.5 - * @since 3.0 Changed signature from isAllUpperCase(String) to - * isAllUpperCase(CharSequence) - */ - public static boolean isAllUpperCase(final CharSequence cs) { - if (isEmpty(cs)) { - return false; - } - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - if (!Character.isUpperCase(cs.charAt(i))) { - return false; - } - } - return true; - } - - /** - *

- * Checks if the CharSequence contains only Unicode letters. - *

- * - *

- * {@code null} will return {@code false}. An empty CharSequence (length()=0) - * will return {@code false}. - *

- * - *
-	 * StringUtils.isAlpha(null)   = false
-	 * StringUtils.isAlpha("")     = false
-	 * StringUtils.isAlpha("  ")   = false
-	 * StringUtils.isAlpha("abc")  = true
-	 * StringUtils.isAlpha("ab2c") = false
-	 * StringUtils.isAlpha("ab-c") = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if only contains letters, and is non-null - * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence) - * @since 3.0 Changed "" to return false and not true - */ - public static boolean isAlpha(final CharSequence cs) { - if (isEmpty(cs)) { - return false; - } - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - if (!Character.isLetter(cs.charAt(i))) { - return false; - } - } - return true; - } - - /** - *

- * Checks if the CharSequence contains only Unicode letters or digits. - *

- * - *

- * {@code null} will return {@code false}. An empty CharSequence (length()=0) - * will return {@code false}. - *

- * - *
-	 * StringUtils.isAlphanumeric(null)   = false
-	 * StringUtils.isAlphanumeric("")     = false
-	 * StringUtils.isAlphanumeric("  ")   = false
-	 * StringUtils.isAlphanumeric("abc")  = true
-	 * StringUtils.isAlphanumeric("ab c") = false
-	 * StringUtils.isAlphanumeric("ab2c") = true
-	 * StringUtils.isAlphanumeric("ab-c") = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if only contains letters or digits, and is non-null - * @since 3.0 Changed signature from isAlphanumeric(String) to - * isAlphanumeric(CharSequence) - * @since 3.0 Changed "" to return false and not true - */ - public static boolean isAlphanumeric(final CharSequence cs) { - if (isEmpty(cs)) { - return false; - } - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - if (!Character.isLetterOrDigit(cs.charAt(i))) { - return false; - } - } - return true; - } - - /** - *

- * Checks if the CharSequence contains only Unicode letters, digits or space - * ({@code ' '}). - *

- * - *

- * {@code null} will return {@code false}. An empty CharSequence (length()=0) - * will return {@code true}. - *

- * - *
-	 * StringUtils.isAlphanumericSpace(null)   = false
-	 * StringUtils.isAlphanumericSpace("")     = true
-	 * StringUtils.isAlphanumericSpace("  ")   = true
-	 * StringUtils.isAlphanumericSpace("abc")  = true
-	 * StringUtils.isAlphanumericSpace("ab c") = true
-	 * StringUtils.isAlphanumericSpace("ab2c") = true
-	 * StringUtils.isAlphanumericSpace("ab-c") = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if only contains letters, digits or space, and is - * non-null - * @since 3.0 Changed signature from isAlphanumericSpace(String) to - * isAlphanumericSpace(CharSequence) - */ - public static boolean isAlphanumericSpace(final CharSequence cs) { - if (cs == null) { - return false; - } - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - final char nowChar = cs.charAt(i); - if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar)) { - return false; - } - } - return true; - } - - /** - *

- * Checks if the CharSequence contains only Unicode letters and space (' '). - *

- * - *

- * {@code null} will return {@code false} An empty CharSequence (length()=0) - * will return {@code true}. - *

- * - *
-	 * StringUtils.isAlphaSpace(null)   = false
-	 * StringUtils.isAlphaSpace("")     = true
-	 * StringUtils.isAlphaSpace("  ")   = true
-	 * StringUtils.isAlphaSpace("abc")  = true
-	 * StringUtils.isAlphaSpace("ab c") = true
-	 * StringUtils.isAlphaSpace("ab2c") = false
-	 * StringUtils.isAlphaSpace("ab-c") = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if only contains letters and space, and is non-null - * @since 3.0 Changed signature from isAlphaSpace(String) to - * isAlphaSpace(CharSequence) - */ - public static boolean isAlphaSpace(final CharSequence cs) { - if (cs == null) { - return false; - } - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - final char nowChar = cs.charAt(i); - if (nowChar != ' ' && !Character.isLetter(nowChar)) { - return false; - } - } - return true; - } - - /** - *

- * Checks if any of the CharSequences are empty ("") or null or whitespace only. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.isAnyBlank((String) null)    = true
-	 * StringUtils.isAnyBlank((String[]) null)  = false
-	 * StringUtils.isAnyBlank(null, "foo")      = true
-	 * StringUtils.isAnyBlank(null, null)       = true
-	 * StringUtils.isAnyBlank("", "bar")        = true
-	 * StringUtils.isAnyBlank("bob", "")        = true
-	 * StringUtils.isAnyBlank("  bob  ", null)  = true
-	 * StringUtils.isAnyBlank(" ", "bar")       = true
-	 * StringUtils.isAnyBlank(new String[] {})  = false
-	 * StringUtils.isAnyBlank(new String[]{""}) = true
-	 * StringUtils.isAnyBlank("foo", "bar")     = false
-	 * 
- * - * @param css the CharSequences to check, may be null or empty - * @return {@code true} if any of the CharSequences are empty or null or - * whitespace only - * @since 3.2 - */ - public static boolean isAnyBlank(final CharSequence... css) { - if (css.length == 0) { - return false; - } - for (final CharSequence cs : css) { - if (isBlank(cs)) { - return true; - } - } - return false; - } - - /** - *

- * Checks if any of the CharSequences are empty ("") or null. - *

- * - *
-	 * StringUtils.isAnyEmpty((String) null)    = true
-	 * StringUtils.isAnyEmpty((String[]) null)  = false
-	 * StringUtils.isAnyEmpty(null, "foo")      = true
-	 * StringUtils.isAnyEmpty("", "bar")        = true
-	 * StringUtils.isAnyEmpty("bob", "")        = true
-	 * StringUtils.isAnyEmpty("  bob  ", null)  = true
-	 * StringUtils.isAnyEmpty(" ", "bar")       = false
-	 * StringUtils.isAnyEmpty("foo", "bar")     = false
-	 * StringUtils.isAnyEmpty(new String[]{})   = false
-	 * StringUtils.isAnyEmpty(new String[]{""}) = true
-	 * 
- * - * @param css the CharSequences to check, may be null or empty - * @return {@code true} if any of the CharSequences are empty or null - * @since 3.2 - */ - public static boolean isAnyEmpty(final CharSequence... css) { - if (css.length == 0) { - return false; - } - for (final CharSequence cs : css) { - if (isEmpty(cs)) { - return true; - } - } - return false; - } - - /** - *

- * Checks if the CharSequence contains only ASCII printable characters. - *

- * - *

- * {@code null} will return {@code false}. An empty CharSequence (length()=0) - * will return {@code true}. - *

- * - *
-	 * StringUtils.isAsciiPrintable(null)     = false
-	 * StringUtils.isAsciiPrintable("")       = true
-	 * StringUtils.isAsciiPrintable(" ")      = true
-	 * StringUtils.isAsciiPrintable("Ceki")   = true
-	 * StringUtils.isAsciiPrintable("ab2c")   = true
-	 * StringUtils.isAsciiPrintable("!ab-c~") = true
-	 * StringUtils.isAsciiPrintable("\u0020") = true
-	 * StringUtils.isAsciiPrintable("\u0021") = true
-	 * StringUtils.isAsciiPrintable("\u007e") = true
-	 * StringUtils.isAsciiPrintable("\u007f") = false
-	 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if every character is in the range 32 thru 126 - * @since 2.1 - * @since 3.0 Changed signature from isAsciiPrintable(String) to - * isAsciiPrintable(CharSequence) - */ - public static boolean isAsciiPrintable(final CharSequence cs) { - if (cs == null) { - return false; - } - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - if (!CharUtils.isAsciiPrintable(cs.charAt(i))) { - return false; - } - } - return true; - } - - /** - *

- * Checks if a CharSequence is empty (""), null or whitespace only. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.isBlank(null)      = true
-	 * StringUtils.isBlank("")        = true
-	 * StringUtils.isBlank(" ")       = true
-	 * StringUtils.isBlank("bob")     = false
-	 * StringUtils.isBlank("  bob  ") = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if the CharSequence is null, empty or whitespace only - * @since 2.0 - * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) - */ - public static boolean isBlank(final CharSequence cs) { - final int strLen = length(cs); - if (strLen == 0) { - return true; - } - for (int i = 0; i < strLen; i++) { - if (!Character.isWhitespace(cs.charAt(i))) { - return false; - } - } - return true; - } - - /** - *

- * Checks if a CharSequence is empty ("") or null. - *

- * - *
-	 * StringUtils.isEmpty(null)      = true
-	 * StringUtils.isEmpty("")        = true
-	 * StringUtils.isEmpty(" ")       = false
-	 * StringUtils.isEmpty("bob")     = false
-	 * StringUtils.isEmpty("  bob  ") = false
-	 * 
- * - *

- * NOTE: This method changed in Lang version 2.0. It no longer trims the - * CharSequence. That functionality is available in isBlank(). - *

- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if the CharSequence is empty or null - * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) - */ - public static boolean isEmpty(final CharSequence cs) { - return cs == null || cs.length() == 0; - } - - /** - *

- * Checks if the CharSequence contains mixed casing of both uppercase and - * lowercase characters. - *

- * - *

- * {@code null} will return {@code false}. An empty CharSequence - * ({@code length()=0}) will return {@code false}. - *

- * - *
-	 * StringUtils.isMixedCase(null)    = false
-	 * StringUtils.isMixedCase("")      = false
-	 * StringUtils.isMixedCase("ABC")   = false
-	 * StringUtils.isMixedCase("abc")   = false
-	 * StringUtils.isMixedCase("aBc")   = true
-	 * StringUtils.isMixedCase("A c")   = true
-	 * StringUtils.isMixedCase("A1c")   = true
-	 * StringUtils.isMixedCase("a/C")   = true
-	 * StringUtils.isMixedCase("aC\t")  = true
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if the CharSequence contains both uppercase and - * lowercase characters - * @since 3.5 - */ - public static boolean isMixedCase(final CharSequence cs) { - if (isEmpty(cs) || cs.length() == 1) { - return false; - } - boolean containsUppercase = false; - boolean containsLowercase = false; - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - if (containsUppercase && containsLowercase) { - return true; - } else if (Character.isUpperCase(cs.charAt(i))) { - containsUppercase = true; - } else if (Character.isLowerCase(cs.charAt(i))) { - containsLowercase = true; - } - } - return containsUppercase && containsLowercase; - } - - /** - *

- * Checks if none of the CharSequences are empty (""), null or whitespace only. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.isNoneBlank((String) null)    = false
-	 * StringUtils.isNoneBlank((String[]) null)  = true
-	 * StringUtils.isNoneBlank(null, "foo")      = false
-	 * StringUtils.isNoneBlank(null, null)       = false
-	 * StringUtils.isNoneBlank("", "bar")        = false
-	 * StringUtils.isNoneBlank("bob", "")        = false
-	 * StringUtils.isNoneBlank("  bob  ", null)  = false
-	 * StringUtils.isNoneBlank(" ", "bar")       = false
-	 * StringUtils.isNoneBlank(new String[] {})  = true
-	 * StringUtils.isNoneBlank(new String[]{""}) = false
-	 * StringUtils.isNoneBlank("foo", "bar")     = true
-	 * 
- * - * @param css the CharSequences to check, may be null or empty - * @return {@code true} if none of the CharSequences are empty or null or - * whitespace only - * @since 3.2 - */ - public static boolean isNoneBlank(final CharSequence... css) { - return !isAnyBlank(css); - } - - /** - *

- * Checks if none of the CharSequences are empty ("") or null. - *

- * - *
-	 * StringUtils.isNoneEmpty((String) null)    = false
-	 * StringUtils.isNoneEmpty((String[]) null)  = true
-	 * StringUtils.isNoneEmpty(null, "foo")      = false
-	 * StringUtils.isNoneEmpty("", "bar")        = false
-	 * StringUtils.isNoneEmpty("bob", "")        = false
-	 * StringUtils.isNoneEmpty("  bob  ", null)  = false
-	 * StringUtils.isNoneEmpty(new String[] {})  = true
-	 * StringUtils.isNoneEmpty(new String[]{""}) = false
-	 * StringUtils.isNoneEmpty(" ", "bar")       = true
-	 * StringUtils.isNoneEmpty("foo", "bar")     = true
-	 * 
- * - * @param css the CharSequences to check, may be null or empty - * @return {@code true} if none of the CharSequences are empty or null - * @since 3.2 - */ - public static boolean isNoneEmpty(final CharSequence... css) { - return !isAnyEmpty(css); - } - - /** - *

- * Checks if a CharSequence is not empty (""), not null and not whitespace only. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.isNotBlank(null)      = false
-	 * StringUtils.isNotBlank("")        = false
-	 * StringUtils.isNotBlank(" ")       = false
-	 * StringUtils.isNotBlank("bob")     = true
-	 * StringUtils.isNotBlank("  bob  ") = true
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if the CharSequence is not empty and not null and not - * whitespace only - * @since 2.0 - * @since 3.0 Changed signature from isNotBlank(String) to - * isNotBlank(CharSequence) - */ - public static boolean isNotBlank(final CharSequence cs) { - return !isBlank(cs); - } - - /** - *

- * Checks if a CharSequence is not empty ("") and not null. - *

- * - *
-	 * StringUtils.isNotEmpty(null)      = false
-	 * StringUtils.isNotEmpty("")        = false
-	 * StringUtils.isNotEmpty(" ")       = true
-	 * StringUtils.isNotEmpty("bob")     = true
-	 * StringUtils.isNotEmpty("  bob  ") = true
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if the CharSequence is not empty and not null - * @since 3.0 Changed signature from isNotEmpty(String) to - * isNotEmpty(CharSequence) - */ - public static boolean isNotEmpty(final CharSequence cs) { - return !isEmpty(cs); - } - - /** - *

- * Checks if the CharSequence contains only Unicode digits. A decimal point is - * not a Unicode digit and returns false. - *

- * - *

- * {@code null} will return {@code false}. An empty CharSequence (length()=0) - * will return {@code false}. - *

- * - *

- * Note that the method does not allow for a leading sign, either positive or - * negative. Also, if a String passes the numeric test, it may still generate a - * NumberFormatException when parsed by Integer.parseInt or Long.parseLong, e.g. - * if the value is outside the range for int or long respectively. - *

- * - *
-	 * StringUtils.isNumeric(null)   = false
-	 * StringUtils.isNumeric("")     = false
-	 * StringUtils.isNumeric("  ")   = false
-	 * StringUtils.isNumeric("123")  = true
-	 * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
-	 * StringUtils.isNumeric("12 3") = false
-	 * StringUtils.isNumeric("ab2c") = false
-	 * StringUtils.isNumeric("12-3") = false
-	 * StringUtils.isNumeric("12.3") = false
-	 * StringUtils.isNumeric("-123") = false
-	 * StringUtils.isNumeric("+123") = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if only contains digits, and is non-null - * @since 3.0 Changed signature from isNumeric(String) to - * isNumeric(CharSequence) - * @since 3.0 Changed "" to return false and not true - */ - public static boolean isNumeric(final CharSequence cs) { - if (isEmpty(cs)) { - return false; - } - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - if (!Character.isDigit(cs.charAt(i))) { - return false; - } - } - return true; - } - - /** - *

- * Checks if the CharSequence contains only Unicode digits or space - * ({@code ' '}). A decimal point is not a Unicode digit and returns false. - *

- * - *

- * {@code null} will return {@code false}. An empty CharSequence (length()=0) - * will return {@code true}. - *

- * - *
-	 * StringUtils.isNumericSpace(null)   = false
-	 * StringUtils.isNumericSpace("")     = true
-	 * StringUtils.isNumericSpace("  ")   = true
-	 * StringUtils.isNumericSpace("123")  = true
-	 * StringUtils.isNumericSpace("12 3") = true
-	 * StringUtils.isNumericSpace("\u0967\u0968\u0969")  = true
-	 * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
-	 * StringUtils.isNumericSpace("ab2c") = false
-	 * StringUtils.isNumericSpace("12-3") = false
-	 * StringUtils.isNumericSpace("12.3") = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if only contains digits or space, and is non-null - * @since 3.0 Changed signature from isNumericSpace(String) to - * isNumericSpace(CharSequence) - */ - public static boolean isNumericSpace(final CharSequence cs) { - if (cs == null) { - return false; - } - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - final char nowChar = cs.charAt(i); - if (nowChar != ' ' && !Character.isDigit(nowChar)) { - return false; - } - } - return true; - } - - /** - *

- * Checks if the CharSequence contains only whitespace. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *

- * {@code null} will return {@code false}. An empty CharSequence (length()=0) - * will return {@code true}. - *

- * - *
-	 * StringUtils.isWhitespace(null)   = false
-	 * StringUtils.isWhitespace("")     = true
-	 * StringUtils.isWhitespace("  ")   = true
-	 * StringUtils.isWhitespace("abc")  = false
-	 * StringUtils.isWhitespace("ab2c") = false
-	 * StringUtils.isWhitespace("ab-c") = false
-	 * 
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if only contains whitespace, and is non-null - * @since 2.0 - * @since 3.0 Changed signature from isWhitespace(String) to - * isWhitespace(CharSequence) - */ - public static boolean isWhitespace(final CharSequence cs) { - if (cs == null) { - return false; - } - final int sz = cs.length(); - for (int i = 0; i < sz; i++) { - if (!Character.isWhitespace(cs.charAt(i))) { - return false; - } - } - return true; - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)              = null
-	 * StringUtils.join([], *)                = ""
-	 * StringUtils.join([null], *)            = ""
-	 * StringUtils.join([false, false], ';')  = "false;false"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @return the joined String, {@code null} if null array input - * @since 3.12.0 - */ - public static String join(final boolean[] array, final char delimiter) { - if (array == null) { - return null; - } - return join(array, delimiter, 0, array.length); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)                   = null
-	 * StringUtils.join([], *)                     = ""
-	 * StringUtils.join([null], *)                 = ""
-	 * StringUtils.join([true, false, true], ';')  = "true;false;true"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the array - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the array - * @return the joined String, {@code null} if null array input - * @since 3.12.0 - */ - public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) { - if (array == null) { - return null; - } - if (endIndex - startIndex <= 0) { - return EMPTY; - } - final StringJoiner joiner = newStringJoiner(delimiter); - for (int i = startIndex; i < endIndex; i++) { - joiner.add(String.valueOf(array[i])); - } - return joiner.toString(); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final byte[] array, final char delimiter) { - if (array == null) { - return null; - } - return join(array, delimiter, 0, array.length); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the array - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the array - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) { - if (array == null) { - return null; - } - if (endIndex - startIndex <= 0) { - return EMPTY; - } - final StringJoiner joiner = newStringJoiner(delimiter); - for (int i = startIndex; i < endIndex; i++) { - joiner.add(String.valueOf(array[i])); - } - return joiner.toString(); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final char[] array, final char delimiter) { - if (array == null) { - return null; - } - return join(array, delimiter, 0, array.length); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the array - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the array - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) { - if (array == null) { - return null; - } - if (endIndex - startIndex <= 0) { - return EMPTY; - } - final StringJoiner joiner = newStringJoiner(delimiter); - for (int i = startIndex; i < endIndex; i++) { - joiner.add(String.valueOf(array[i])); - } - return joiner.toString(); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final double[] array, final char delimiter) { - if (array == null) { - return null; - } - return join(array, delimiter, 0, array.length); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the array - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the array - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) { - if (array == null) { - return null; - } - if (endIndex - startIndex <= 0) { - return EMPTY; - } - final StringJoiner joiner = newStringJoiner(delimiter); - for (int i = startIndex; i < endIndex; i++) { - joiner.add(String.valueOf(array[i])); - } - return joiner.toString(); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final float[] array, final char delimiter) { - if (array == null) { - return null; - } - return join(array, delimiter, 0, array.length); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the array - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the array - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) { - if (array == null) { - return null; - } - if (endIndex - startIndex <= 0) { - return EMPTY; - } - final StringJoiner joiner = newStringJoiner(delimiter); - for (int i = startIndex; i < endIndex; i++) { - joiner.add(String.valueOf(array[i])); - } - return joiner.toString(); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param separator the separator character to use - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final int[] array, final char separator) { - if (array == null) { - return null; - } - return join(array, separator, 0, array.length); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the array - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the array - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) { - if (array == null) { - return null; - } - if (endIndex - startIndex <= 0) { - return EMPTY; - } - final StringJoiner joiner = newStringJoiner(delimiter); - for (int i = startIndex; i < endIndex; i++) { - joiner.add(String.valueOf(array[i])); - } - return joiner.toString(); - } - - /** - *

- * Joins the elements of the provided {@code Iterable} into a single String - * containing the provided elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the iteration are represented by empty strings. - *

- * - *

- * See the examples here: {@link #join(Object[],char)}. - *

- * - * @param iterable the {@code Iterable} providing the values to join together, - * may be null - * @param separator the separator character to use - * @return the joined String, {@code null} if null iterator input - * @since 2.3 - */ - public static String join(final Iterable iterable, final char separator) { - if (iterable == null) { - return null; - } - return join(iterable.iterator(), separator); - } - - /** - *

- * Joins the elements of the provided {@code Iterable} into a single String - * containing the provided elements. - *

- * - *

- * No delimiter is added before or after the list. A {@code null} separator is - * the same as an empty String (""). - *

- * - *

- * See the examples here: {@link #join(Object[],String)}. - *

- * - * @param iterable the {@code Iterable} providing the values to join together, - * may be null - * @param separator the separator character to use, null treated as "" - * @return the joined String, {@code null} if null iterator input - * @since 2.3 - */ - public static String join(final Iterable iterable, final String separator) { - if (iterable == null) { - return null; - } - return join(iterable.iterator(), separator); - } - - /** - *

- * Joins the elements of the provided {@code Iterator} into a single String - * containing the provided elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the iteration are represented by empty strings. - *

- * - *

- * See the examples here: {@link #join(Object[],char)}. - *

- * - * @param iterator the {@code Iterator} of values to join together, may be null - * @param separator the separator character to use - * @return the joined String, {@code null} if null iterator input - * @since 2.0 - */ - public static String join(final Iterator iterator, final char separator) { - - // handle null, zero and one elements before building a buffer - if (iterator == null) { - return null; - } - if (!iterator.hasNext()) { - return EMPTY; - } - final Object first = iterator.next(); - if (!iterator.hasNext()) { - return toStringOrEmpty(first); - } - - // two or more elements - final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small - if (first != null) { - buf.append(first); - } - - while (iterator.hasNext()) { - buf.append(separator); - final Object obj = iterator.next(); - if (obj != null) { - buf.append(obj); - } - } - - return buf.toString(); - } - - /** - *

- * Joins the elements of the provided {@code Iterator} into a single String - * containing the provided elements. - *

- * - *

- * No delimiter is added before or after the list. A {@code null} separator is - * the same as an empty String (""). - *

- * - *

- * See the examples here: {@link #join(Object[],String)}. - *

- * - * @param iterator the {@code Iterator} of values to join together, may be null - * @param separator the separator character to use, null treated as "" - * @return the joined String, {@code null} if null iterator input - */ - public static String join(final Iterator iterator, final String separator) { - - // handle null, zero and one elements before building a buffer - if (iterator == null) { - return null; - } - if (!iterator.hasNext()) { - return EMPTY; - } - final Object first = iterator.next(); - if (!iterator.hasNext()) { - return Objects.toString(first, ""); - } - - // two or more elements - final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small - if (first != null) { - buf.append(first); - } - - while (iterator.hasNext()) { - if (separator != null) { - buf.append(separator); - } - final Object obj = iterator.next(); - if (obj != null) { - buf.append(obj); - } - } - return buf.toString(); - } - - /** - *

- * Joins the elements of the provided {@code List} into a single String - * containing the provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
-	 * StringUtils.join(["a", "b", "c"], null) = "abc"
-	 * StringUtils.join([null, "", "a"], ';')  = ";;a"
-	 * 
- * - * @param list the {@code List} of values to join together, may be null - * @param separator the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the list - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the list - * @return the joined String, {@code null} if null list input - * @since 3.8 - */ - public static String join(final List list, final char separator, final int startIndex, final int endIndex) { - if (list == null) { - return null; - } - final int noOfItems = endIndex - startIndex; - if (noOfItems <= 0) { - return EMPTY; - } - final List subList = list.subList(startIndex, endIndex); - return join(subList.iterator(), separator); - } - - /** - *

- * Joins the elements of the provided {@code List} into a single String - * containing the provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
-	 * StringUtils.join(["a", "b", "c"], null) = "abc"
-	 * StringUtils.join([null, "", "a"], ';')  = ";;a"
-	 * 
- * - * @param list the {@code List} of values to join together, may be null - * @param separator the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the list - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the list - * @return the joined String, {@code null} if null list input - * @since 3.8 - */ - public static String join(final List list, final String separator, final int startIndex, final int endIndex) { - if (list == null) { - return null; - } - final int noOfItems = endIndex - startIndex; - if (noOfItems <= 0) { - return EMPTY; - } - final List subList = list.subList(startIndex, endIndex); - return join(subList.iterator(), separator); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param separator the separator character to use - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final long[] array, final char separator) { - if (array == null) { - return null; - } - return join(array, separator, 0, array.length); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the array - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the array - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) { - if (array == null) { - return null; - } - if (endIndex - startIndex <= 0) { - return EMPTY; - } - final StringJoiner joiner = newStringJoiner(delimiter); - for (int i = startIndex; i < endIndex; i++) { - joiner.add(String.valueOf(array[i])); - } - return joiner.toString(); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
-	 * StringUtils.join(["a", "b", "c"], null) = "abc"
-	 * StringUtils.join([null, "", "a"], ';')  = ";;a"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @return the joined String, {@code null} if null array input - * @since 2.0 - */ - public static String join(final Object[] array, final char delimiter) { - if (array == null) { - return null; - } - return join(array, delimiter, 0, array.length); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
-	 * StringUtils.join(["a", "b", "c"], null) = "abc"
-	 * StringUtils.join([null, "", "a"], ';')  = ";;a"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the array - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the array - * @return the joined String, {@code null} if null array input - * @since 2.0 - */ - public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) { - if (array == null) { - return null; - } - if (endIndex - startIndex <= 0) { - return EMPTY; - } - final StringJoiner joiner = newStringJoiner(delimiter); - for (int i = startIndex; i < endIndex; i++) { - joiner.add(toStringOrEmpty(array[i])); - } - return joiner.toString(); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. A {@code null} separator is - * the same as an empty String (""). Null objects or empty strings within the - * array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)                = null
-	 * StringUtils.join([], *)                  = ""
-	 * StringUtils.join([null], *)              = ""
-	 * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
-	 * StringUtils.join(["a", "b", "c"], null)  = "abc"
-	 * StringUtils.join(["a", "b", "c"], "")    = "abc"
-	 * StringUtils.join([null, "", "a"], ',')   = ",,a"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use, null treated as "" - * @return the joined String, {@code null} if null array input - */ - public static String join(final Object[] array, final String delimiter) { - if (array == null) { - return null; - } - return join(array, delimiter, 0, array.length); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. A {@code null} separator is - * the same as an empty String (""). Null objects or empty strings within the - * array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *, *, *)                = null
-	 * StringUtils.join([], *, *, *)                  = ""
-	 * StringUtils.join([null], *, *, *)              = ""
-	 * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
-	 * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
-	 * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
-	 * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
-	 * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
-	 * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
-	 * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use, null treated as "" - * @param startIndex the first index to start joining from. - * @param endIndex the index to stop joining from (exclusive). - * @return the joined String, {@code null} if null array input; or the empty - * string if {@code endIndex - startIndex <= 0}. The number of joined - * entries is given by {@code endIndex - startIndex} - * @throws ArrayIndexOutOfBoundsException ife
- * {@code startIndex < 0} or
- * {@code startIndex >= array.length()} - * or
- * {@code endIndex < 0} or
- * {@code endIndex > array.length()} - */ - public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) { - if (array == null) { - return null; - } - if (endIndex - startIndex <= 0) { - return EMPTY; - } - final StringJoiner joiner = new StringJoiner(toStringOrEmpty(delimiter)); - for (int i = startIndex; i < endIndex; i++) { - joiner.add(toStringOrEmpty(array[i])); - } - return joiner.toString(); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final short[] array, final char delimiter) { - if (array == null) { - return null; - } - return join(array, delimiter, 0, array.length); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No delimiter is added before or after the list. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null, *)               = null
-	 * StringUtils.join([], *)                 = ""
-	 * StringUtils.join([null], *)             = ""
-	 * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
-	 * StringUtils.join([1, 2, 3], null) = "123"
-	 * 
- * - * @param array the array of values to join together, may be null - * @param delimiter the separator character to use - * @param startIndex the first index to start joining from. It is an error to - * pass in a start index past the end of the array - * @param endIndex the index to stop joining from (exclusive). It is an error - * to pass in an end index past the end of the array - * @return the joined String, {@code null} if null array input - * @since 3.2 - */ - public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) { - if (array == null) { - return null; - } - if (endIndex - startIndex <= 0) { - return EMPTY; - } - final StringJoiner joiner = newStringJoiner(delimiter); - for (int i = startIndex; i < endIndex; i++) { - joiner.add(String.valueOf(array[i])); - } - return joiner.toString(); - } - - /** - *

- * Joins the elements of the provided array into a single String containing the - * provided list of elements. - *

- * - *

- * No separator is added to the joined String. Null objects or empty strings - * within the array are represented by empty strings. - *

- * - *
-	 * StringUtils.join(null)            = null
-	 * StringUtils.join([])              = ""
-	 * StringUtils.join([null])          = ""
-	 * StringUtils.join(["a", "b", "c"]) = "abc"
-	 * StringUtils.join([null, "", "a"]) = "a"
-	 * 
- * - * @param the specific type of values to join together - * @param elements the values to join together, may be null - * @return the joined String, {@code null} if null array input - * @since 2.0 - * @since 3.0 Changed signature to use varargs - */ - @SafeVarargs - public static String join(final T... elements) { - return join(elements, null); - } - - /** - *

- * Joins the elements of the provided varargs into a single String containing - * the provided elements. - *

- * - *

- * No delimiter is added before or after the list. {@code null} elements and - * separator are treated as empty Strings (""). - *

- * - *
-	 * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
-	 * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
-	 * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
-	 * StringUtils.joinWith(null, {"a", "b"})       = "ab"
-	 * 
- * - * @param delimiter the separator character to use, null treated as "" - * @param array the varargs providing the values to join together. - * {@code null} elements are treated as "" - * @return the joined String. - * @throws java.lang.IllegalArgumentException if a null varargs is provided - * @since 3.5 - */ - public static String joinWith(final String delimiter, final Object... array) { - if (array == null) { - throw new IllegalArgumentException("Object varargs must not be null"); - } - return join(array, delimiter); - } - - /** - *

- * Finds the last index within a CharSequence, handling {@code null}. This - * method uses {@link String#lastIndexOf(String)} if possible. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. - *

- * - *
-	 * StringUtils.lastIndexOf(null, *)          = -1
-	 * StringUtils.lastIndexOf(*, null)          = -1
-	 * StringUtils.lastIndexOf("", "")           = 0
-	 * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
-	 * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
-	 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
-	 * StringUtils.lastIndexOf("aabaabaa", "")   = 8
-	 * 
- * - * @param seq the CharSequence to check, may be null - * @param searchSeq the CharSequence to find, may be null - * @return the last index of the search String, -1 if no match or {@code null} - * string input - * @since 2.0 - * @since 3.0 Changed signature from lastIndexOf(String, String) to - * lastIndexOf(CharSequence, CharSequence) - */ - public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) { - if (seq == null) { - return INDEX_NOT_FOUND; - } - return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length()); - } - - /** - *

- * Finds the last index within a CharSequence, handling {@code null}. This - * method uses {@link String#lastIndexOf(String, int)} if possible. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. A negative start position - * returns {@code -1}. An empty ("") search CharSequence always matches unless - * the start position is negative. A start position greater than the string - * length searches the whole string. The search starts at the startPos and works - * backwards; matches starting after the start position are ignored. - *

- * - *
-	 * StringUtils.lastIndexOf(null, *, *)          = -1
-	 * StringUtils.lastIndexOf(*, null, *)          = -1
-	 * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
-	 * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
-	 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
-	 * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
-	 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
-	 * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
-	 * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
-	 * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
-	 * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
-	 * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
-	 * 
- * - * @param seq the CharSequence to check, may be null - * @param searchSeq the CharSequence to find, may be null - * @param startPos the start position, negative treated as zero - * @return the last index of the search CharSequence (always ≤ startPos), -1 - * if no match or {@code null} string input - * @since 2.0 - * @since 3.0 Changed signature from lastIndexOf(String, String, int) to - * lastIndexOf(CharSequence, CharSequence, int) - */ - public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { - return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos); - } - - /** - * Returns the index within {@code seq} of the last occurrence of the specified - * character. For values of {@code searchChar} in the range from 0 to 0xFFFF - * (inclusive), the index (in Unicode code units) returned is the largest value - * k such that:
- * - *
-	 * this.charAt(k) == searchChar
-	 * 
- * - *
is true. For other values of {@code searchChar}, it is the - * largest value k such that:
- * - *
-	 * this.codePointAt(k) == searchChar
-	 * 
- * - *
is true. In either case, if no such character occurs in this - * string, then {@code -1} is returned. Furthermore, a {@code null} or empty - * ("") {@code CharSequence} will return {@code -1}. The {@code seq} - * {@code CharSequence} object is searched backwards starting at the last - * character. - * - *
-	 * StringUtils.lastIndexOf(null, *)         = -1
-	 * StringUtils.lastIndexOf("", *)           = -1
-	 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
-	 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
-	 * 
- * - * @param seq the {@code CharSequence} to check, may be null - * @param searchChar the character to find - * @return the last index of the search character, -1 if no match or - * {@code null} string input - * @since 2.0 - * @since 3.0 Changed signature from lastIndexOf(String, int) to - * lastIndexOf(CharSequence, int) - * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like - * {@code String} - */ - public static int lastIndexOf(final CharSequence seq, final int searchChar) { - if (isEmpty(seq)) { - return INDEX_NOT_FOUND; - } - return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length()); - } - - /** - * Returns the index within {@code seq} of the last occurrence of the specified - * character, searching backward starting at the specified index. For values of - * {@code searchChar} in the range from 0 to 0xFFFF (inclusive), the index - * returned is the largest value k such that:
- * - *
-	 * (this.charAt(k) == searchChar) && (k <= startPos)
-	 * 
- * - *
is true. For other values of {@code searchChar}, it is the - * largest value k such that:
- * - *
-	 * (this.codePointAt(k) == searchChar) && (k <= startPos)
-	 * 
- * - *
is true. In either case, if no such character occurs in - * {@code seq} at or before position {@code startPos}, then {@code -1} is - * returned. Furthermore, a {@code null} or empty ("") {@code CharSequence} will - * return {@code -1}. A start position greater than the string length searches - * the whole string. The search starts at the {@code startPos} and works - * backwards; matches starting after the start position are ignored. - * - *

- * All indices are specified in {@code char} values (Unicode code units). - * - *

-	 * StringUtils.lastIndexOf(null, *, *)          = -1
-	 * StringUtils.lastIndexOf("", *,  *)           = -1
-	 * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
-	 * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
-	 * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
-	 * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
-	 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
-	 * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
-	 * 
- * - * @param seq the CharSequence to check, may be null - * @param searchChar the character to find - * @param startPos the start position - * @return the last index of the search character (always ≤ startPos), -1 if - * no match or {@code null} string input - * @since 2.0 - * @since 3.0 Changed signature from lastIndexOf(String, int, int) to - * lastIndexOf(CharSequence, int, int) - */ - public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) { - if (isEmpty(seq)) { - return INDEX_NOT_FOUND; - } - return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos); - } - - /** - *

- * Find the latest index of any substring in a set of potential substrings. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. A {@code null} search - * array will return {@code -1}. A {@code null} or zero length search array - * entry will be ignored, but a search array containing "" will return the - * length of {@code str} if {@code str} is not null. This method uses - * {@link String#indexOf(String)} if possible - *

- * - *
-	 * StringUtils.lastIndexOfAny(null, *)                    = -1
-	 * StringUtils.lastIndexOfAny(*, null)                    = -1
-	 * StringUtils.lastIndexOfAny(*, [])                      = -1
-	 * StringUtils.lastIndexOfAny(*, [null])                  = -1
-	 * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
-	 * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
-	 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
-	 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
-	 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param searchStrs the CharSequences to search for, may be null - * @return the last index of any of the CharSequences, -1 if no match - * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to - * lastIndexOfAny(CharSequence, CharSequence) - */ - public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) { - if (str == null || searchStrs == null) { - return INDEX_NOT_FOUND; - } - int ret = INDEX_NOT_FOUND; - int tmp = 0; - for (final CharSequence search : searchStrs) { - if (search == null) { - continue; - } - tmp = CharSequenceUtils.lastIndexOf(str, search, str.length()); - if (tmp > ret) { - ret = tmp; - } - } - return ret; - } - - /** - *

- * Case in-sensitive find of the last index within a CharSequence. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. A negative start position - * returns {@code -1}. An empty ("") search CharSequence always matches unless - * the start position is negative. A start position greater than the string - * length searches the whole string. - *

- * - *
-	 * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
-	 * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
-	 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
-	 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
-	 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @return the first index of the search CharSequence, -1 if no match or - * {@code null} string input - * @since 2.5 - * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to - * lastIndexOfIgnoreCase(CharSequence, CharSequence) - */ - public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { - if (str == null || searchStr == null) { - return INDEX_NOT_FOUND; - } - return lastIndexOfIgnoreCase(str, searchStr, str.length()); - } - - /** - *

- * Case in-sensitive find of the last index within a CharSequence from the - * specified position. - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. A negative start position - * returns {@code -1}. An empty ("") search CharSequence always matches unless - * the start position is negative. A start position greater than the string - * length searches the whole string. The search starts at the startPos and works - * backwards; matches starting after the start position are ignored. - *

- * - *
-	 * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
-	 * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
-	 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
-	 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
-	 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
-	 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
-	 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
-	 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
-	 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @param startPos the start position - * @return the last index of the search CharSequence (always ≤ startPos), -1 - * if no match or {@code null} input - * @since 2.5 - * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) - * to lastIndexOfIgnoreCase(CharSequence, CharSequence, int) - */ - public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { - if (str == null || searchStr == null) { - return INDEX_NOT_FOUND; - } - final int searchStrLength = searchStr.length(); - final int strLength = str.length(); - if (startPos > strLength - searchStrLength) { - startPos = strLength - searchStrLength; - } - if (startPos < 0) { - return INDEX_NOT_FOUND; - } - if (searchStrLength == 0) { - return startPos; - } - - for (int i = startPos; i >= 0; i--) { - if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStrLength)) { - return i; - } - } - return INDEX_NOT_FOUND; - } - - /** - *

- * Finds the n-th last index within a String, handling {@code null}. This method - * uses {@link String#lastIndexOf(String)}. - *

- * - *

- * A {@code null} String will return {@code -1}. - *

- * - *
-	 * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
-	 * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
-	 * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
-	 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
-	 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
-	 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
-	 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
-	 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
-	 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
-	 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
-	 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
-	 * 
- * - *

- * Note that 'tail(CharSequence str, int n)' may be implemented as: - *

- * - *
-	 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @param ordinal the n-th last {@code searchStr} to find - * @return the n-th last index of the search CharSequence, {@code -1} - * ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input - * @since 2.5 - * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to - * lastOrdinalIndexOf(CharSequence, CharSequence, int) - */ - public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { - return ordinalIndexOf(str, searchStr, ordinal, true); - } - - /** - *

- * Gets the leftmost {@code len} characters of a String. - *

- * - *

- * If {@code len} characters are not available, or the String is {@code null}, - * the String will be returned without an exception. An empty String is returned - * if len is negative. - *

- * - *
-	 * StringUtils.left(null, *)    = null
-	 * StringUtils.left(*, -ve)     = ""
-	 * StringUtils.left("", *)      = ""
-	 * StringUtils.left("abc", 0)   = ""
-	 * StringUtils.left("abc", 2)   = "ab"
-	 * StringUtils.left("abc", 4)   = "abc"
-	 * 
- * - * @param str the String to get the leftmost characters from, may be null - * @param len the length of the required String - * @return the leftmost characters, {@code null} if null String input - */ - public static String left(final String str, final int len) { - if (str == null) { - return null; - } - if (len < 0) { - return EMPTY; - } - if (str.length() <= len) { - return str; - } - return str.substring(0, len); - } - - /** - *

- * Left pad a String with spaces (' '). - *

- * - *

- * The String is padded to the size of {@code size}. - *

- * - *
-	 * StringUtils.leftPad(null, *)   = null
-	 * StringUtils.leftPad("", 3)     = "   "
-	 * StringUtils.leftPad("bat", 3)  = "bat"
-	 * StringUtils.leftPad("bat", 5)  = "  bat"
-	 * StringUtils.leftPad("bat", 1)  = "bat"
-	 * StringUtils.leftPad("bat", -1) = "bat"
-	 * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @return left padded String or original String if no padding is necessary, - * {@code null} if null String input - */ - public static String leftPad(final String str, final int size) { - return leftPad(str, size, ' '); - } - - /** - *

- * Left pad a String with a specified character. - *

- * - *

- * Pad to a size of {@code size}. - *

- * - *
-	 * StringUtils.leftPad(null, *, *)     = null
-	 * StringUtils.leftPad("", 3, 'z')     = "zzz"
-	 * StringUtils.leftPad("bat", 3, 'z')  = "bat"
-	 * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
-	 * StringUtils.leftPad("bat", 1, 'z')  = "bat"
-	 * StringUtils.leftPad("bat", -1, 'z') = "bat"
-	 * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @param padChar the character to pad with - * @return left padded String or original String if no padding is necessary, - * {@code null} if null String input - * @since 2.0 - */ - public static String leftPad(final String str, final int size, final char padChar) { - if (str == null) { - return null; - } - final int pads = size - str.length(); - if (pads <= 0) { - return str; // returns original String when possible - } - if (pads > PAD_LIMIT) { - return leftPad(str, size, String.valueOf(padChar)); - } - return repeat(padChar, pads).concat(str); - } - - /** - *

- * Left pad a String with a specified String. - *

- * - *

- * Pad to a size of {@code size}. - *

- * - *
-	 * StringUtils.leftPad(null, *, *)      = null
-	 * StringUtils.leftPad("", 3, "z")      = "zzz"
-	 * StringUtils.leftPad("bat", 3, "yz")  = "bat"
-	 * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
-	 * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
-	 * StringUtils.leftPad("bat", 1, "yz")  = "bat"
-	 * StringUtils.leftPad("bat", -1, "yz") = "bat"
-	 * StringUtils.leftPad("bat", 5, null)  = "  bat"
-	 * StringUtils.leftPad("bat", 5, "")    = "  bat"
-	 * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @param padStr the String to pad with, null or empty treated as single space - * @return left padded String or original String if no padding is necessary, - * {@code null} if null String input - */ - public static String leftPad(final String str, final int size, String padStr) { - if (str == null) { - return null; - } - if (isEmpty(padStr)) { - padStr = SPACE; - } - final int padLen = padStr.length(); - final int strLen = str.length(); - final int pads = size - strLen; - if (pads <= 0) { - return str; // returns original String when possible - } - if (padLen == 1 && pads <= PAD_LIMIT) { - return leftPad(str, size, padStr.charAt(0)); - } - - if (pads == padLen) { - return padStr.concat(str); - } else if (pads < padLen) { - return padStr.substring(0, pads).concat(str); - } else { - final char[] padding = new char[pads]; - final char[] padChars = padStr.toCharArray(); - for (int i = 0; i < pads; i++) { - padding[i] = padChars[i % padLen]; - } - return new String(padding).concat(str); - } - } - - /** - * Gets a CharSequence length or {@code 0} if the CharSequence is {@code null}. - * - * @param cs a CharSequence or {@code null} - * @return CharSequence length or {@code 0} if the CharSequence is {@code null}. - * @since 2.4 - * @since 3.0 Changed signature from length(String) to length(CharSequence) - */ - public static int length(final CharSequence cs) { - return cs == null ? 0 : cs.length(); - } - - /** - *

- * Converts a String to lower case as per {@link String#toLowerCase()}. - *

- * - *

- * A {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.lowerCase(null)  = null
-	 * StringUtils.lowerCase("")    = ""
-	 * StringUtils.lowerCase("aBc") = "abc"
-	 * 
- * - *

- * Note: As described in the documentation for - * {@link String#toLowerCase()}, the result of this method is affected by the - * current locale. For platform-independent case transformations, the method - * {@link #lowerCase(String, Locale)} should be used with a specific locale - * (e.g. {@link Locale#ENGLISH}). - *

- * - * @param str the String to lower case, may be null - * @return the lower cased String, {@code null} if null String input - */ - public static String lowerCase(final String str) { - if (str == null) { - return null; - } - return str.toLowerCase(); - } - - /** - *

- * Converts a String to lower case as per {@link String#toLowerCase(Locale)}. - *

- * - *

- * A {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
-	 * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
-	 * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
-	 * 
- * - * @param str the String to lower case, may be null - * @param locale the locale that defines the case transformation rules, must not - * be null - * @return the lower cased String, {@code null} if null String input - * @since 2.5 - */ - public static String lowerCase(final String str, final Locale locale) { - if (str == null) { - return null; - } - return str.toLowerCase(LocaleUtils.toLocale(locale)); - } - - private static int[] matches(final CharSequence first, final CharSequence second) { - final CharSequence max; - final CharSequence min; - if (first.length() > second.length()) { - max = first; - min = second; - } else { - max = second; - min = first; - } - final int range = Math.max(max.length() / 2 - 1, 0); - final int[] matchIndexes = new int[min.length()]; - Arrays.fill(matchIndexes, -1); - final boolean[] matchFlags = new boolean[max.length()]; - int matches = 0; - for (int mi = 0; mi < min.length(); mi++) { - final char c1 = min.charAt(mi); - for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) { - if (!matchFlags[xi] && c1 == max.charAt(xi)) { - matchIndexes[mi] = xi; - matchFlags[xi] = true; - matches++; - break; - } - } - } - final char[] ms1 = new char[matches]; - final char[] ms2 = new char[matches]; - for (int i = 0, si = 0; i < min.length(); i++) { - if (matchIndexes[i] != -1) { - ms1[si] = min.charAt(i); - si++; - } - } - for (int i = 0, si = 0; i < max.length(); i++) { - if (matchFlags[i]) { - ms2[si] = max.charAt(i); - si++; - } - } - int transpositions = 0; - for (int mi = 0; mi < ms1.length; mi++) { - if (ms1[mi] != ms2[mi]) { - transpositions++; - } - } - int prefix = 0; - for (int mi = 0; mi < min.length(); mi++) { - if (first.charAt(mi) == second.charAt(mi)) { - prefix++; - } else { - break; - } - } - return new int[] { matches, transpositions / 2, prefix, max.length() }; - } - - /** - *

- * Gets {@code len} characters from the middle of a String. - *

- * - *

- * If {@code len} characters are not available, the remainder of the String will - * be returned without an exception. If the String is {@code null}, {@code null} - * will be returned. An empty String is returned if len is negative or exceeds - * the length of {@code str}. - *

- * - *
-	 * StringUtils.mid(null, *, *)    = null
-	 * StringUtils.mid(*, *, -ve)     = ""
-	 * StringUtils.mid("", 0, *)      = ""
-	 * StringUtils.mid("abc", 0, 2)   = "ab"
-	 * StringUtils.mid("abc", 0, 4)   = "abc"
-	 * StringUtils.mid("abc", 2, 4)   = "c"
-	 * StringUtils.mid("abc", 4, 2)   = ""
-	 * StringUtils.mid("abc", -2, 2)  = "ab"
-	 * 
- * - * @param str the String to get the characters from, may be null - * @param pos the position to start from, negative treated as zero - * @param len the length of the required String - * @return the middle characters, {@code null} if null String input - */ - public static String mid(final String str, int pos, final int len) { - if (str == null) { - return null; - } - if (len < 0 || pos > str.length()) { - return EMPTY; - } - if (pos < 0) { - pos = 0; - } - if (str.length() <= pos + len) { - return str.substring(pos); - } - return str.substring(pos, pos + len); - } - - private static StringJoiner newStringJoiner(final char delimiter) { - return new StringJoiner(String.valueOf(delimiter)); - } - - /** - *

- * Similar to http://www.w3.org/TR/xpath/#function-normalize - * -space - *

- *

- * The function returns the argument string with whitespace normalized by using - * {@code {@link #trim(String)}} to remove leading and trailing whitespace and - * then replacing sequences of whitespace characters by a single space. - *

- * In XML Whitespace characters are the same as those allowed by the - * S production, which is S ::= - * (#x20 | #x9 | #xD | #xA)+ - *

- * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] - * - *

- * For reference: - *

- *
    - *
  • \x0B = vertical tab
  • - *
  • \f = #xC = form feed
  • - *
  • #x20 = space
  • - *
  • #x9 = \t
  • - *
  • #xA = \n
  • - *
  • #xD = \r
  • - *
- * - *

- * The difference is that Java's whitespace includes vertical tab and form feed, - * which this functional will also normalize. Additionally {@code {@link - * #trim(String)}} removes control characters (char <= 32) from both ends of - * this String. - *

- * - * @see Pattern - * @see #trim(String) - * @see http://www.w3.org/TR/xpath/#function-normalize-space - * @param str the source String to normalize whitespaces from, may be null - * @return the modified string with whitespace normalized, {@code null} if null - * String input - * - * @since 3.0 - */ - public static String normalizeSpace(final String str) { - // LANG-1020: Improved performance significantly by normalizing manually instead - // of using regex - // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for - // performance test - if (isEmpty(str)) { - return str; - } - final int size = str.length(); - final char[] newChars = new char[size]; - int count = 0; - int whitespacesCount = 0; - boolean startWhitespaces = true; - for (int i = 0; i < size; i++) { - final char actualChar = str.charAt(i); - final boolean isWhitespace = Character.isWhitespace(actualChar); - if (isWhitespace) { - if (whitespacesCount == 0 && !startWhitespaces) { - newChars[count++] = SPACE.charAt(0); - } - whitespacesCount++; - } else { - startWhitespaces = false; - newChars[count++] = (actualChar == 160 ? 32 : actualChar); - whitespacesCount = 0; - } - } - if (startWhitespaces) { - return EMPTY; - } - return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim(); - } - - /** - *

- * Finds the n-th index within a CharSequence, handling {@code null}. This - * method uses {@link String#indexOf(String)} if possible. - *

- *

- * Note: The code starts looking for a match at the start of the target, - * incrementing the starting index by one after each successful match (unless - * {@code searchStr} is an empty string in which case the position is never - * incremented and {@code 0} is returned immediately). This means that matches - * may overlap. - *

- *

- * A {@code null} CharSequence will return {@code -1}. - *

- * - *
-	 * StringUtils.ordinalIndexOf(null, *, *)          = -1
-	 * StringUtils.ordinalIndexOf(*, null, *)          = -1
-	 * StringUtils.ordinalIndexOf("", "", *)           = 0
-	 * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
-	 * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
-	 * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
-	 * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
-	 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
-	 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
-	 * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
-	 * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
-	 * 
- * - *

- * Matches may overlap: - *

- * - *
-	 * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
-	 * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
-	 * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
-	 *
-	 * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
-	 * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
-	 * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
-	 * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
-	 * 
- * - *

- * Note that 'head(CharSequence str, int n)' may be implemented as: - *

- * - *
-	 * str.substring(0, lastOrdinalIndexOf(str, "\n", n))
-	 * 
- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @param ordinal the n-th {@code searchStr} to find - * @return the n-th index of the search CharSequence, {@code -1} - * ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input - * @since 2.1 - * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to - * ordinalIndexOf(CharSequence, CharSequence, int) - */ - public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { - return ordinalIndexOf(str, searchStr, ordinal, false); - } - - /** - *

- * Finds the n-th index within a String, handling {@code null}. This method uses - * {@link String#indexOf(String)} if possible. - *

- *

- * Note that matches may overlap - *

- * - *

- * A {@code null} CharSequence will return {@code -1}. - *

- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @param ordinal the n-th {@code searchStr} to find, overlapping matches are - * allowed. - * @param lastIndex true if lastOrdinalIndexOf() otherwise false if - * ordinalIndexOf() - * @return the n-th index of the search CharSequence, {@code -1} - * ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input - */ - // Shared code between ordinalIndexOf(String, String, int) and - // lastOrdinalIndexOf(String, String, int) - private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, - final boolean lastIndex) { - if (str == null || searchStr == null || ordinal <= 0) { - return INDEX_NOT_FOUND; - } - if (searchStr.length() == 0) { - return lastIndex ? str.length() : 0; - } - int found = 0; - // set the initial index beyond the end of the string - // this is to allow for the initial index decrement/increment - int index = lastIndex ? str.length() : INDEX_NOT_FOUND; - do { - if (lastIndex) { - index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string - } else { - index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string - } - if (index < 0) { - return index; - } - found++; - } while (found < ordinal); - return index; - } - - /** - *

- * Overlays part of a String with another String. - *

- * - *

- * A {@code null} string input returns {@code null}. A negative index is treated - * as zero. An index greater than the string length is treated as the string - * length. The start index is always the smaller of the two indices. - *

- * - *
-	 * StringUtils.overlay(null, *, *, *)            = null
-	 * StringUtils.overlay("", "abc", 0, 0)          = "abc"
-	 * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
-	 * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
-	 * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
-	 * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
-	 * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
-	 * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
-	 * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
-	 * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
-	 * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
-	 * 
- * - * @param str the String to do overlaying in, may be null - * @param overlay the String to overlay, may be null - * @param start the position to start overlaying at - * @param end the position to stop overlaying before - * @return overlayed String, {@code null} if null String input - * @since 2.0 - */ - public static String overlay(final String str, String overlay, int start, int end) { - if (str == null) { - return null; - } - if (overlay == null) { - overlay = EMPTY; - } - final int len = str.length(); - if (start < 0) { - start = 0; - } - if (start > len) { - start = len; - } - if (end < 0) { - end = 0; - } - if (end > len) { - end = len; - } - if (start > end) { - final int temp = start; - start = end; - end = temp; - } - return str.substring(0, start) + overlay + str.substring(end); - } - - /** - * Prepends the prefix to the start of the string if the string does not already - * start with any of the prefixes. - * - * @param str The string. - * @param prefix The prefix to prepend to the start of the string. - * @param ignoreCase Indicates whether the compare should ignore case. - * @param prefixes Additional prefixes that are valid (optional). - * - * @return A new String if prefix was prepended, the same string otherwise. - */ - private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, - final CharSequence... prefixes) { - if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) { - return str; - } - if (prefixes.length > 0) { - for (final CharSequence p : prefixes) { - if (startsWith(str, p, ignoreCase)) { - return str; - } - } - } - return prefix.toString() + str; - } - - /** - * Prepends the prefix to the start of the string if the string does not already - * start with any of the prefixes. - * - *
-	 * StringUtils.prependIfMissing(null, null) = null
-	 * StringUtils.prependIfMissing("abc", null) = "abc"
-	 * StringUtils.prependIfMissing("", "xyz") = "xyz"
-	 * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
-	 * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
-	 * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
-	 * 
- *

- * With additional prefixes, - *

- * - *
-	 * StringUtils.prependIfMissing(null, null, null) = null
-	 * StringUtils.prependIfMissing("abc", null, null) = "abc"
-	 * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
-	 * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
-	 * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
-	 * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
-	 * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
-	 * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
-	 * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
-	 * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
-	 * 
- * - * @param str The string. - * @param prefix The prefix to prepend to the start of the string. - * @param prefixes Additional prefixes that are valid. - * - * @return A new String if prefix was prepended, the same string otherwise. - * - * @since 3.2 - */ - public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) { - return prependIfMissing(str, prefix, false, prefixes); - } - - /** - * Prepends the prefix to the start of the string if the string does not already - * start, case insensitive, with any of the prefixes. - * - *
-	 * StringUtils.prependIfMissingIgnoreCase(null, null) = null
-	 * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
-	 * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
-	 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
-	 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
-	 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
-	 * 
- *

- * With additional prefixes, - *

- * - *
-	 * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
-	 * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
-	 * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
-	 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
-	 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
-	 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
-	 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
-	 * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
-	 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
-	 * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
-	 * 
- * - * @param str The string. - * @param prefix The prefix to prepend to the start of the string. - * @param prefixes Additional prefixes that are valid (optional). - * - * @return A new String if prefix was prepended, the same string otherwise. - * - * @since 3.2 - */ - public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, - final CharSequence... prefixes) { - return prependIfMissing(str, prefix, true, prefixes); - } - - /** - *

- * Removes all occurrences of a character from within the source string. - *

- * - *

- * A {@code null} source string will return {@code null}. An empty ("") source - * string will return the empty string. - *

- * - *
-	 * StringUtils.remove(null, *)       = null
-	 * StringUtils.remove("", *)         = ""
-	 * StringUtils.remove("queued", 'u') = "qeed"
-	 * StringUtils.remove("queued", 'z') = "queued"
-	 * 
- * - * @param str the source String to search, may be null - * @param remove the char to search for and remove, may be null - * @return the substring with the char removed if found, {@code null} if null - * String input - * @since 2.1 - */ - public static String remove(final String str, final char remove) { - if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) { - return str; - } - final char[] chars = str.toCharArray(); - int pos = 0; - for (int i = 0; i < chars.length; i++) { - if (chars[i] != remove) { - chars[pos++] = chars[i]; - } - } - return new String(chars, 0, pos); - } - - /** - *

- * Removes all occurrences of a substring from within the source string. - *

- * - *

- * A {@code null} source string will return {@code null}. An empty ("") source - * string will return the empty string. A {@code null} remove string will return - * the source string. An empty ("") remove string will return the source string. - *

- * - *
-	 * StringUtils.remove(null, *)        = null
-	 * StringUtils.remove("", *)          = ""
-	 * StringUtils.remove(*, null)        = *
-	 * StringUtils.remove(*, "")          = *
-	 * StringUtils.remove("queued", "ue") = "qd"
-	 * StringUtils.remove("queued", "zz") = "queued"
-	 * 
- * - * @param str the source String to search, may be null - * @param remove the String to search for and remove, may be null - * @return the substring with the string removed if found, {@code null} if null - * String input - * @since 2.1 - */ - public static String remove(final String str, final String remove) { - if (isEmpty(str) || isEmpty(remove)) { - return str; - } - return replace(str, remove, EMPTY, -1); - } - - /** - *

- * Removes each substring of the text String that matches the given regular - * expression. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code text.replaceAll(regex, StringUtils.EMPTY)}
  • - *
  • {@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *

- * Unlike in the {@link #removePattern(String, String)} method, the - * {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL - * option prepend {@code "(?s)"} to the regex. DOTALL is also known as - * single-line mode in Perl. - *

- * - *
-	 * StringUtils.removeAll(null, *)      = null
-	 * StringUtils.removeAll("any", (String) null)  = "any"
-	 * StringUtils.removeAll("any", "")    = "any"
-	 * StringUtils.removeAll("any", ".*")  = ""
-	 * StringUtils.removeAll("any", ".+")  = ""
-	 * StringUtils.removeAll("abc", ".?")  = ""
-	 * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
-	 * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
-	 * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
-	 * 
- * - * @param text text to remove from, may be null - * @param regex the regular expression to which this string is to be matched - * @return the text with any removes processed, {@code null} if null String - * input - * - * @throws java.util.regex.PatternSyntaxException if the regular expression's - * syntax is invalid - * - * @see #replaceAll(String, String, String) - * @see #removePattern(String, String) - * @see String#replaceAll(String, String) - * @see java.util.regex.Pattern - * @see java.util.regex.Pattern#DOTALL - * @since 3.5 - * - * @deprecated Moved to RegExUtils. - */ - @Deprecated - public static String removeAll(final String text, final String regex) { - return RegExUtils.removeAll(text, regex); - } - - /** - *

- * Removes a substring only if it is at the end of a source string, otherwise - * returns the source string. - *

- * - *

- * A {@code null} source string will return {@code null}. An empty ("") source - * string will return the empty string. A {@code null} search string will return - * the source string. - *

- * - *
-	 * StringUtils.removeEnd(null, *)      = null
-	 * StringUtils.removeEnd("", *)        = ""
-	 * StringUtils.removeEnd(*, null)      = *
-	 * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
-	 * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
-	 * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
-	 * StringUtils.removeEnd("abc", "")    = "abc"
-	 * 
- * - * @param str the source String to search, may be null - * @param remove the String to search for and remove, may be null - * @return the substring with the string removed if found, {@code null} if null - * String input - * @since 2.1 - */ - public static String removeEnd(final String str, final String remove) { - if (isEmpty(str) || isEmpty(remove)) { - return str; - } - if (str.endsWith(remove)) { - return str.substring(0, str.length() - remove.length()); - } - return str; - } - - /** - *

- * Case insensitive removal of a substring if it is at the end of a source - * string, otherwise returns the source string. - *

- * - *

- * A {@code null} source string will return {@code null}. An empty ("") source - * string will return the empty string. A {@code null} search string will return - * the source string. - *

- * - *
-	 * StringUtils.removeEndIgnoreCase(null, *)      = null
-	 * StringUtils.removeEndIgnoreCase("", *)        = ""
-	 * StringUtils.removeEndIgnoreCase(*, null)      = *
-	 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
-	 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
-	 * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
-	 * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
-	 * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
-	 * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
-	 * 
- * - * @param str the source String to search, may be null - * @param remove the String to search for (case insensitive) and remove, may be - * null - * @return the substring with the string removed if found, {@code null} if null - * String input - * @since 2.4 - */ - public static String removeEndIgnoreCase(final String str, final String remove) { - if (isEmpty(str) || isEmpty(remove)) { - return str; - } - if (endsWithIgnoreCase(str, remove)) { - return str.substring(0, str.length() - remove.length()); - } - return str; - } - - /** - *

- * Removes the first substring of the text string that matches the given regular - * expression. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code text.replaceFirst(regex, StringUtils.EMPTY)}
  • - *
  • {@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *

- * The {@link Pattern#DOTALL} option is NOT automatically added. To use the - * DOTALL option prepend {@code "(?s)"} to the regex. DOTALL is also known as - * single-line mode in Perl. - *

- * - *
-	 * StringUtils.removeFirst(null, *)      = null
-	 * StringUtils.removeFirst("any", (String) null)  = "any"
-	 * StringUtils.removeFirst("any", "")    = "any"
-	 * StringUtils.removeFirst("any", ".*")  = ""
-	 * StringUtils.removeFirst("any", ".+")  = ""
-	 * StringUtils.removeFirst("abc", ".?")  = "bc"
-	 * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
-	 * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
-	 * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
-	 * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
-	 * 
- * - * @param text text to remove from, may be null - * @param regex the regular expression to which this string is to be matched - * @return the text with the first replacement processed, {@code null} if null - * String input - * - * @throws java.util.regex.PatternSyntaxException if the regular expression's - * syntax is invalid - * - * @see #replaceFirst(String, String, String) - * @see String#replaceFirst(String, String) - * @see java.util.regex.Pattern - * @see java.util.regex.Pattern#DOTALL - * @since 3.5 - * - * @deprecated Moved to RegExUtils. - */ - @Deprecated - public static String removeFirst(final String text, final String regex) { - return replaceFirst(text, regex, EMPTY); - } - - /** - *

- * Case insensitive removal of all occurrences of a substring from within the - * source string. - *

- * - *

- * A {@code null} source string will return {@code null}. An empty ("") source - * string will return the empty string. A {@code null} remove string will return - * the source string. An empty ("") remove string will return the source string. - *

- * - *
-	 * StringUtils.removeIgnoreCase(null, *)        = null
-	 * StringUtils.removeIgnoreCase("", *)          = ""
-	 * StringUtils.removeIgnoreCase(*, null)        = *
-	 * StringUtils.removeIgnoreCase(*, "")          = *
-	 * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
-	 * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
-	 * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
-	 * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
-	 * 
- * - * @param str the source String to search, may be null - * @param remove the String to search for (case insensitive) and remove, may be - * null - * @return the substring with the string removed if found, {@code null} if null - * String input - * @since 3.5 - */ - public static String removeIgnoreCase(final String str, final String remove) { - return replaceIgnoreCase(str, remove, EMPTY, -1); - } - - /** - *

- * Removes each substring of the source String that matches the given regular - * expression using the DOTALL option. - *

- * - * This call is a {@code null} safe equivalent to: - *
    - *
  • {@code source.replaceAll("(?s)" + regex, StringUtils.EMPTY)}
  • - *
  • {@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.removePattern(null, *)       = null
-	 * StringUtils.removePattern("any", (String) null)   = "any"
-	 * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
-	 * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
-	 * 
- * - * @param source the source string - * @param regex the regular expression to which this string is to be matched - * @return The resulting {@code String} - * @see #replacePattern(String, String, String) - * @see String#replaceAll(String, String) - * @see Pattern#DOTALL - * @since 3.2 - * @since 3.5 Changed {@code null} reference passed to this method is a no-op. - * - * @deprecated Moved to RegExUtils. - */ - @Deprecated - public static String removePattern(final String source, final String regex) { - return RegExUtils.removePattern(source, regex); - } - - /** - *

- * Removes a substring only if it is at the beginning of a source string, - * otherwise returns the source string. - *

- * - *

- * A {@code null} source string will return {@code null}. An empty ("") source - * string will return the empty string. A {@code null} search string will return - * the source string. - *

- * - *
-	 * StringUtils.removeStart(null, *)      = null
-	 * StringUtils.removeStart("", *)        = ""
-	 * StringUtils.removeStart(*, null)      = *
-	 * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
-	 * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
-	 * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
-	 * StringUtils.removeStart("abc", "")    = "abc"
-	 * 
- * - * @param str the source String to search, may be null - * @param remove the String to search for and remove, may be null - * @return the substring with the string removed if found, {@code null} if null - * String input - * @since 2.1 - */ - public static String removeStart(final String str, final String remove) { - if (isEmpty(str) || isEmpty(remove)) { - return str; - } - if (str.startsWith(remove)) { - return str.substring(remove.length()); - } - return str; - } - - /** - *

- * Case insensitive removal of a substring if it is at the beginning of a source - * string, otherwise returns the source string. - *

- * - *

- * A {@code null} source string will return {@code null}. An empty ("") source - * string will return the empty string. A {@code null} search string will return - * the source string. - *

- * - *
-	 * StringUtils.removeStartIgnoreCase(null, *)      = null
-	 * StringUtils.removeStartIgnoreCase("", *)        = ""
-	 * StringUtils.removeStartIgnoreCase(*, null)      = *
-	 * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
-	 * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
-	 * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
-	 * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
-	 * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
-	 * 
- * - * @param str the source String to search, may be null - * @param remove the String to search for (case insensitive) and remove, may be - * null - * @return the substring with the string removed if found, {@code null} if null - * String input - * @since 2.4 - */ - public static String removeStartIgnoreCase(final String str, final String remove) { - if (str != null && startsWithIgnoreCase(str, remove)) { - return str.substring(length(remove)); - } - return str; - } - - /** - *

- * Returns padding using the specified delimiter repeated to a given length. - *

- * - *
-	 * StringUtils.repeat('e', 0)  = ""
-	 * StringUtils.repeat('e', 3)  = "eee"
-	 * StringUtils.repeat('e', -2) = ""
-	 * 
- * - *

- * Note: this method does not support padding with - * Unicode - * Supplementary Characters as they require a pair of {@code char}s to be - * represented. If you are needing to support full I18N of your applications - * consider using {@link #repeat(String, int)} instead. - *

- * - * @param ch character to repeat - * @param repeat number of times to repeat char, negative treated as zero - * @return String with repeated character - * @see #repeat(String, int) - */ - public static String repeat(final char ch, final int repeat) { - if (repeat <= 0) { - return EMPTY; - } - final char[] buf = new char[repeat]; - Arrays.fill(buf, ch); - return new String(buf); - } - - /** - *

- * Repeat a String {@code repeat} times to form a new String. - *

- * - *
-	 * StringUtils.repeat(null, 2) = null
-	 * StringUtils.repeat("", 0)   = ""
-	 * StringUtils.repeat("", 2)   = ""
-	 * StringUtils.repeat("a", 3)  = "aaa"
-	 * StringUtils.repeat("ab", 2) = "abab"
-	 * StringUtils.repeat("a", -2) = ""
-	 * 
- * - * @param str the String to repeat, may be null - * @param repeat number of times to repeat str, negative treated as zero - * @return a new String consisting of the original String repeated, {@code null} - * if null String input - */ - public static String repeat(final String str, final int repeat) { - // Performance tuned for 2.0 (JDK1.4) - if (str == null) { - return null; - } - if (repeat <= 0) { - return EMPTY; - } - final int inputLength = str.length(); - if (repeat == 1 || inputLength == 0) { - return str; - } - if (inputLength == 1 && repeat <= PAD_LIMIT) { - return repeat(str.charAt(0), repeat); - } - - final int outputLength = inputLength * repeat; - switch (inputLength) { - case 1: - return repeat(str.charAt(0), repeat); - case 2: - final char ch0 = str.charAt(0); - final char ch1 = str.charAt(1); - final char[] output2 = new char[outputLength]; - for (int i = repeat * 2 - 2; i >= 0; i--, i--) { - output2[i] = ch0; - output2[i + 1] = ch1; - } - return new String(output2); - default: - final StringBuilder buf = new StringBuilder(outputLength); - for (int i = 0; i < repeat; i++) { - buf.append(str); - } - return buf.toString(); - } - } - - /** - *

- * Repeat a String {@code repeat} times to form a new String, with a String - * separator injected each time. - *

- * - *
-	 * StringUtils.repeat(null, null, 2) = null
-	 * StringUtils.repeat(null, "x", 2)  = null
-	 * StringUtils.repeat("", null, 0)   = ""
-	 * StringUtils.repeat("", "", 2)     = ""
-	 * StringUtils.repeat("", "x", 3)    = "xxx"
-	 * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
-	 * 
- * - * @param str the String to repeat, may be null - * @param separator the String to inject, may be null - * @param repeat number of times to repeat str, negative treated as zero - * @return a new String consisting of the original String repeated, {@code null} - * if null String input - * @since 2.5 - */ - public static String repeat(final String str, final String separator, final int repeat) { - if (str == null || separator == null) { - return repeat(str, repeat); - } - // given that repeat(String, int) is quite optimized, better to rely on it than - // try and splice this into it - final String result = repeat(str + separator, repeat); - return removeEnd(result, separator); - } - - /** - *

- * Replaces all occurrences of a String within another String. - *

- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replace(null, *, *)        = null
-	 * StringUtils.replace("", *, *)          = ""
-	 * StringUtils.replace("any", null, *)    = "any"
-	 * StringUtils.replace("any", *, null)    = "any"
-	 * StringUtils.replace("any", "", *)      = "any"
-	 * StringUtils.replace("aba", "a", null)  = "aba"
-	 * StringUtils.replace("aba", "a", "")    = "b"
-	 * StringUtils.replace("aba", "a", "z")   = "zbz"
-	 * 
- * - * @see #replace(String text, String searchString, String replacement, int max) - * @param text text to search and replace in, may be null - * @param searchString the String to search for, may be null - * @param replacement the String to replace it with, may be null - * @return the text with any replacements processed, {@code null} if null String - * input - */ - public static String replace(final String text, final String searchString, final String replacement) { - return replace(text, searchString, replacement, -1); - } - - /** - *

- * Replaces a String with another String inside a larger String, for the first - * {@code max} values of the search String. - *

- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replace(null, *, *, *)         = null
-	 * StringUtils.replace("", *, *, *)           = ""
-	 * StringUtils.replace("any", null, *, *)     = "any"
-	 * StringUtils.replace("any", *, null, *)     = "any"
-	 * StringUtils.replace("any", "", *, *)       = "any"
-	 * StringUtils.replace("any", *, *, 0)        = "any"
-	 * StringUtils.replace("abaa", "a", null, -1) = "abaa"
-	 * StringUtils.replace("abaa", "a", "", -1)   = "b"
-	 * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
-	 * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
-	 * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
-	 * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
-	 * 
- * - * @param text text to search and replace in, may be null - * @param searchString the String to search for, may be null - * @param replacement the String to replace it with, may be null - * @param max maximum number of values to replace, or {@code -1} if no - * maximum - * @return the text with any replacements processed, {@code null} if null String - * input - */ - public static String replace(final String text, final String searchString, final String replacement, - final int max) { - return replace(text, searchString, replacement, max, false); - } - - /** - *

- * Replaces a String with another String inside a larger String, for the first - * {@code max} values of the search String, case sensitively/insensitively based - * on {@code ignoreCase} value. - *

- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replace(null, *, *, *, false)         = null
-	 * StringUtils.replace("", *, *, *, false)           = ""
-	 * StringUtils.replace("any", null, *, *, false)     = "any"
-	 * StringUtils.replace("any", *, null, *, false)     = "any"
-	 * StringUtils.replace("any", "", *, *, false)       = "any"
-	 * StringUtils.replace("any", *, *, 0, false)        = "any"
-	 * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
-	 * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
-	 * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
-	 * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
-	 * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
-	 * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
-	 * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
-	 * 
- * - * @param text text to search and replace in, may be null - * @param searchString the String to search for (case insensitive), may be null - * @param replacement the String to replace it with, may be null - * @param max maximum number of values to replace, or {@code -1} if no - * maximum - * @param ignoreCase if true replace is case insensitive, otherwise case - * sensitive - * @return the text with any replacements processed, {@code null} if null String - * input - */ - private static String replace(final String text, String searchString, final String replacement, int max, - final boolean ignoreCase) { - if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { - return text; - } - if (ignoreCase) { - searchString = searchString.toLowerCase(); - } - int start = 0; - int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start); - if (end == INDEX_NOT_FOUND) { - return text; - } - final int replLength = searchString.length(); - int increase = Math.max(replacement.length() - replLength, 0); - increase *= max < 0 ? 16 : Math.min(max, 64); - final StringBuilder buf = new StringBuilder(text.length() + increase); - while (end != INDEX_NOT_FOUND) { - buf.append(text, start, end).append(replacement); - start = end + replLength; - if (--max == 0) { - break; - } - end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start); - } - buf.append(text, start, text.length()); - return buf.toString(); - } - - /** - *

- * Replaces each substring of the text String that matches the given regular - * expression with the given replacement. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code text.replaceAll(regex, replacement)}
  • - *
  • {@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *

- * Unlike in the {@link #replacePattern(String, String, String)} method, the - * {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL - * option prepend {@code "(?s)"} to the regex. DOTALL is also known as - * single-line mode in Perl. - *

- * - *
-	 * StringUtils.replaceAll(null, *, *)       = null
-	 * StringUtils.replaceAll("any", (String) null, *)   = "any"
-	 * StringUtils.replaceAll("any", *, null)   = "any"
-	 * StringUtils.replaceAll("", "", "zzz")    = "zzz"
-	 * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
-	 * StringUtils.replaceAll("", ".+", "zzz")  = ""
-	 * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
-	 * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")      = "z\nz"
-	 * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")  = "z"
-	 * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
-	 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
-	 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
-	 * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
-	 * 
- * - * @param text text to search and replace in, may be null - * @param regex the regular expression to which this string is to be - * matched - * @param replacement the string to be substituted for each match - * @return the text with any replacements processed, {@code null} if null String - * input - * - * @throws java.util.regex.PatternSyntaxException if the regular expression's - * syntax is invalid - * - * @see #replacePattern(String, String, String) - * @see String#replaceAll(String, String) - * @see java.util.regex.Pattern - * @see java.util.regex.Pattern#DOTALL - * @since 3.5 - * - * @deprecated Moved to RegExUtils. - */ - @Deprecated - public static String replaceAll(final String text, final String regex, final String replacement) { - return RegExUtils.replaceAll(text, regex, replacement); - } - - /** - *

- * Replaces all occurrences of a character in a String with another. This is a - * null-safe version of {@link String#replace(char, char)}. - *

- * - *

- * A {@code null} string input returns {@code null}. An empty ("") string input - * returns an empty string. - *

- * - *
-	 * StringUtils.replaceChars(null, *, *)        = null
-	 * StringUtils.replaceChars("", *, *)          = ""
-	 * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
-	 * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
-	 * 
- * - * @param str String to replace characters in, may be null - * @param searchChar the character to search for, may be null - * @param replaceChar the character to replace, may be null - * @return modified String, {@code null} if null string input - * @since 2.0 - */ - public static String replaceChars(final String str, final char searchChar, final char replaceChar) { - if (str == null) { - return null; - } - return str.replace(searchChar, replaceChar); - } - - /** - *

- * Replaces multiple characters in a String in one go. This method can also be - * used to delete characters. - *

- * - *

- * For example:
- * {@code replaceChars("hello", "ho", "jy") = jelly}. - *

- * - *

- * A {@code null} string input returns {@code null}. An empty ("") string input - * returns an empty string. A null or empty set of search characters returns the - * input string. - *

- * - *

- * The length of the search characters should normally equal the length of the - * replace characters. If the search characters is longer, then the extra search - * characters are deleted. If the search characters is shorter, then the extra - * replace characters are ignored. - *

- * - *
-	 * StringUtils.replaceChars(null, *, *)           = null
-	 * StringUtils.replaceChars("", *, *)             = ""
-	 * StringUtils.replaceChars("abc", null, *)       = "abc"
-	 * StringUtils.replaceChars("abc", "", *)         = "abc"
-	 * StringUtils.replaceChars("abc", "b", null)     = "ac"
-	 * StringUtils.replaceChars("abc", "b", "")       = "ac"
-	 * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
-	 * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
-	 * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
-	 * 
- * - * @param str String to replace characters in, may be null - * @param searchChars a set of characters to search for, may be null - * @param replaceChars a set of characters to replace, may be null - * @return modified String, {@code null} if null string input - * @since 2.0 - */ - public static String replaceChars(final String str, final String searchChars, String replaceChars) { - if (isEmpty(str) || isEmpty(searchChars)) { - return str; - } - if (replaceChars == null) { - replaceChars = EMPTY; - } - boolean modified = false; - final int replaceCharsLength = replaceChars.length(); - final int strLength = str.length(); - final StringBuilder buf = new StringBuilder(strLength); - for (int i = 0; i < strLength; i++) { - final char ch = str.charAt(i); - final int index = searchChars.indexOf(ch); - if (index >= 0) { - modified = true; - if (index < replaceCharsLength) { - buf.append(replaceChars.charAt(index)); - } - } else { - buf.append(ch); - } - } - if (modified) { - return buf.toString(); - } - return str; - } - - /** - *

- * Replaces all occurrences of Strings within another String. - *

- * - *

- * A {@code null} reference passed to this method is a no-op, or if any "search - * string" or "string to replace" is null, that replace will be ignored. This - * will not repeat. For repeating replaces, call the overloaded method. - *

- * - *
-	 *  StringUtils.replaceEach(null, *, *)        = null
-	 *  StringUtils.replaceEach("", *, *)          = ""
-	 *  StringUtils.replaceEach("aba", null, null) = "aba"
-	 *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
-	 *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
-	 *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
-	 *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
-	 *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
-	 *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
-	 *  (example of how it does not repeat)
-	 *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
-	 * 
- * - * @param text text to search and replace in, no-op if null - * @param searchList the Strings to search for, no-op if null - * @param replacementList the Strings to replace them with, no-op if null - * @return the text with any replacements processed, {@code null} if null String - * input - * @throws IllegalArgumentException if the lengths of the arrays are not the - * same (null is ok, and/or size 0) - * @since 2.4 - */ - public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) { - return replaceEach(text, searchList, replacementList, false, 0); - } - - /** - *

- * Replace all occurrences of Strings within another String. This is a private - * recursive helper method for - * {@link #replaceEachRepeatedly(String, String[], String[])} and - * {@link #replaceEach(String, String[], String[])} - *

- * - *

- * A {@code null} reference passed to this method is a no-op, or if any "search - * string" or "string to replace" is null, that replace will be ignored. - *

- * - *
-	 *  StringUtils.replaceEach(null, *, *, *, *) = null
-	 *  StringUtils.replaceEach("", *, *, *, *) = ""
-	 *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
-	 *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
-	 *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
-	 *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
-	 *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
-	 *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
-	 *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
-	 *  (example of how it repeats)
-	 *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
-	 *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
-	 *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
-	 * 
- * - * @param text text to search and replace in, no-op if null - * @param searchList the Strings to search for, no-op if null - * @param replacementList the Strings to replace them with, no-op if null - * @param repeat if true, then replace repeatedly until there are no - * more possible replacements or timeToLive < 0 - * @param timeToLive if less than 0 then there is a circular reference and - * endless loop - * @return the text with any replacements processed, {@code null} if null String - * input - * @throws IllegalStateException if the search is repeating and there is an - * endless loop due to outputs of one being - * inputs to another - * @throws IllegalArgumentException if the lengths of the arrays are not the - * same (null is ok, and/or size 0) - * @since 2.4 - */ - private static String replaceEach(final String text, final String[] searchList, final String[] replacementList, - final boolean repeat, final int timeToLive) { - - // mchyzer Performance note: This creates very few new objects (one major goal) - // let me know if there are performance requests, we can create a harness to - // measure - - // if recursing, this shouldn't be less than 0 - if (timeToLive < 0) { - final Set searchSet = new HashSet<>(Arrays.asList(searchList)); - final Set replacementSet = new HashSet<>(Arrays.asList(replacementList)); - searchSet.retainAll(replacementSet); - if (!searchSet.isEmpty()) { - throw new IllegalStateException("Aborting to protect against StackOverflowError - " - + "output of one loop is the input of another"); - } - } - - if (isEmpty(text) || searchList.length == 0 || replacementList.length == 0 - || (searchList.length > 0 && timeToLive == -1)) { - return text; - } - - final int searchLength = searchList.length; - final int replacementLength = replacementList.length; - - // make sure lengths are ok, these need to be equal - if (searchLength != replacementLength) { - throw new IllegalArgumentException( - "Search and Replace array lengths don't match: " + searchLength + " vs " + replacementLength); - } - - // keep track of which still have matches - final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; - - // index on index that the match was found - int textIndex = -1; - int replaceIndex = -1; - int tempIndex = -1; - - // index of replace array that will replace the search string found - // NOTE: logic duplicated below START - for (int i = 0; i < searchLength; i++) { - if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) { - continue; - } - tempIndex = text.indexOf(searchList[i]); - - // see if we need to keep searching for this - if (tempIndex == -1) { - noMoreMatchesForReplIndex[i] = true; - } else if (textIndex == -1 || tempIndex < textIndex) { - textIndex = tempIndex; - replaceIndex = i; - } - } - // NOTE: logic mostly below END - - // no search strings found, we are done - if (textIndex == -1) { - return text; - } - - int start = 0; - - // get a good guess on the size of the result buffer so it doesn't have to - // double if it goes over a bit - int increase = 0; - - // count the replacement text elements that are larger than their corresponding - // text being replaced - for (int i = 0; i < searchList.length; i++) { - if (searchList[i] == null || replacementList[i] == null) { - continue; - } - final int greater = replacementList[i].length() - searchList[i].length(); - if (greater > 0) { - increase += 3 * greater; // assume 3 matches - } - } - // have upper-bound at 20% increase, then let Java take over - increase = Math.min(increase, text.length() / 5); - - final StringBuilder buf = new StringBuilder(text.length() + increase); - - while (textIndex != -1) { - - for (int i = start; i < textIndex; i++) { - buf.append(text.charAt(i)); - } - buf.append(replacementList[replaceIndex]); - - start = textIndex + searchList[replaceIndex].length(); - - textIndex = -1; - replaceIndex = -1; - // find the next earliest match - // NOTE: logic mostly duplicated above START - for (int i = 0; i < searchLength; i++) { - if (noMoreMatchesForReplIndex[i] || searchList[i] == null || searchList[i].isEmpty() - || replacementList[i] == null) { - continue; - } - tempIndex = text.indexOf(searchList[i], start); - - // see if we need to keep searching for this - if (tempIndex == -1) { - noMoreMatchesForReplIndex[i] = true; - } else if (textIndex == -1 || tempIndex < textIndex) { - textIndex = tempIndex; - replaceIndex = i; - } - } - // NOTE: logic duplicated above END - - } - final int textLength = text.length(); - for (int i = start; i < textLength; i++) { - buf.append(text.charAt(i)); - } - final String result = buf.toString(); - if (!repeat) { - return result; - } - - return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); - } - - /** - *

- * Replaces all occurrences of Strings within another String. - *

- * - *

- * A {@code null} reference passed to this method is a no-op, or if any "search - * string" or "string to replace" is null, that replace will be ignored. - *

- * - *
-	 *  StringUtils.replaceEachRepeatedly(null, *, *) = null
-	 *  StringUtils.replaceEachRepeatedly("", *, *) = ""
-	 *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
-	 *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
-	 *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
-	 *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
-	 *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
-	 *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
-	 *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
-	 *  (example of how it repeats)
-	 *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
-	 *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
-	 * 
- * - * @param text text to search and replace in, no-op if null - * @param searchList the Strings to search for, no-op if null - * @param replacementList the Strings to replace them with, no-op if null - * @return the text with any replacements processed, {@code null} if null String - * input - * @throws IllegalStateException if the search is repeating and there is an - * endless loop due to outputs of one being - * inputs to another - * @throws IllegalArgumentException if the lengths of the arrays are not the - * same (null is ok, and/or size 0) - * @since 2.4 - */ - public static String replaceEachRepeatedly(final String text, final String[] searchList, - final String[] replacementList) { - // timeToLive should be 0 if not used or nothing to replace, else it's - // the length of the replace array - final int timeToLive = searchList == null ? 0 : searchList.length; - return replaceEach(text, searchList, replacementList, true, timeToLive); - } - - /** - *

- * Replaces the first substring of the text string that matches the given - * regular expression with the given replacement. - *

- * - * This method is a {@code null} safe equivalent to: - *
    - *
  • {@code text.replaceFirst(regex, replacement)}
  • - *
  • {@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *

- * The {@link Pattern#DOTALL} option is NOT automatically added. To use the - * DOTALL option prepend {@code "(?s)"} to the regex. DOTALL is also known as - * single-line mode in Perl. - *

- * - *
-	 * StringUtils.replaceFirst(null, *, *)       = null
-	 * StringUtils.replaceFirst("any", (String) null, *)   = "any"
-	 * StringUtils.replaceFirst("any", *, null)   = "any"
-	 * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
-	 * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
-	 * StringUtils.replaceFirst("", ".+", "zzz")  = ""
-	 * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
-	 * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
-	 * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
-	 * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
-	 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
-	 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
-	 * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
-	 * 
- * - * @param text text to search and replace in, may be null - * @param regex the regular expression to which this string is to be - * matched - * @param replacement the string to be substituted for the first match - * @return the text with the first replacement processed, {@code null} if null - * String input - * - * @throws java.util.regex.PatternSyntaxException if the regular expression's - * syntax is invalid - * - * @see String#replaceFirst(String, String) - * @see java.util.regex.Pattern - * @see java.util.regex.Pattern#DOTALL - * @since 3.5 - * - * @deprecated Moved to RegExUtils. - */ - @Deprecated - public static String replaceFirst(final String text, final String regex, final String replacement) { - return RegExUtils.replaceFirst(text, regex, replacement); - } - - /** - *

- * Case insensitively replaces all occurrences of a String within another - * String. - *

- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replaceIgnoreCase(null, *, *)        = null
-	 * StringUtils.replaceIgnoreCase("", *, *)          = ""
-	 * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
-	 * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
-	 * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
-	 * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
-	 * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
-	 * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
-	 * 
- * - * @see #replaceIgnoreCase(String text, String searchString, String replacement, - * int max) - * @param text text to search and replace in, may be null - * @param searchString the String to search for (case insensitive), may be null - * @param replacement the String to replace it with, may be null - * @return the text with any replacements processed, {@code null} if null String - * input - * @since 3.5 - */ - public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) { - return replaceIgnoreCase(text, searchString, replacement, -1); - } - - /** - *

- * Case insensitively replaces a String with another String inside a larger - * String, for the first {@code max} values of the search String. - *

- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
-	 * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
-	 * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
-	 * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
-	 * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
-	 * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
-	 * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
-	 * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
-	 * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
-	 * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
-	 * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
-	 * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
-	 * 
- * - * @param text text to search and replace in, may be null - * @param searchString the String to search for (case insensitive), may be null - * @param replacement the String to replace it with, may be null - * @param max maximum number of values to replace, or {@code -1} if no - * maximum - * @return the text with any replacements processed, {@code null} if null String - * input - * @since 3.5 - */ - public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, - final int max) { - return replace(text, searchString, replacement, max, true); - } - - /** - *

- * Replaces a String with another String inside a larger String, once. - *

- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replaceOnce(null, *, *)        = null
-	 * StringUtils.replaceOnce("", *, *)          = ""
-	 * StringUtils.replaceOnce("any", null, *)    = "any"
-	 * StringUtils.replaceOnce("any", *, null)    = "any"
-	 * StringUtils.replaceOnce("any", "", *)      = "any"
-	 * StringUtils.replaceOnce("aba", "a", null)  = "aba"
-	 * StringUtils.replaceOnce("aba", "a", "")    = "ba"
-	 * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
-	 * 
- * - * @see #replace(String text, String searchString, String replacement, int max) - * @param text text to search and replace in, may be null - * @param searchString the String to search for, may be null - * @param replacement the String to replace with, may be null - * @return the text with any replacements processed, {@code null} if null String - * input - */ - public static String replaceOnce(final String text, final String searchString, final String replacement) { - return replace(text, searchString, replacement, 1); - } - - /** - *

- * Case insensitively replaces a String with another String inside a larger - * String, once. - *

- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
-	 * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
-	 * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
-	 * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
-	 * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
-	 * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
-	 * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
-	 * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
-	 * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
-	 * 
- * - * @see #replaceIgnoreCase(String text, String searchString, String replacement, - * int max) - * @param text text to search and replace in, may be null - * @param searchString the String to search for (case insensitive), may be null - * @param replacement the String to replace with, may be null - * @return the text with any replacements processed, {@code null} if null String - * input - * @since 3.5 - */ - public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) { - return replaceIgnoreCase(text, searchString, replacement, 1); - } - - /** - *

- * Replaces each substring of the source String that matches the given regular - * expression with the given replacement using the {@link Pattern#DOTALL} - * option. DOTALL is also known as single-line mode in Perl. - *

- * - * This call is a {@code null} safe equivalent to: - *
    - *
  • {@code source.replaceAll("(?s)" + regex, replacement)}
  • - *
  • {@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}
  • - *
- * - *

- * A {@code null} reference passed to this method is a no-op. - *

- * - *
-	 * StringUtils.replacePattern(null, *, *)       = null
-	 * StringUtils.replacePattern("any", (String) null, *)   = "any"
-	 * StringUtils.replacePattern("any", *, null)   = "any"
-	 * StringUtils.replacePattern("", "", "zzz")    = "zzz"
-	 * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
-	 * StringUtils.replacePattern("", ".+", "zzz")  = ""
-	 * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
-	 * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
-	 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
-	 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
-	 * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
-	 * 
- * - * @param source the source string - * @param regex the regular expression to which this string is to be - * matched - * @param replacement the string to be substituted for each match - * @return The resulting {@code String} - * @see #replaceAll(String, String, String) - * @see String#replaceAll(String, String) - * @see Pattern#DOTALL - * @since 3.2 - * @since 3.5 Changed {@code null} reference passed to this method is a no-op. - * - * @deprecated Moved to RegExUtils. - */ - @Deprecated - public static String replacePattern(final String source, final String regex, final String replacement) { - return RegExUtils.replacePattern(source, regex, replacement); - } - - /** - *

- * Reverses a String as per {@link StringBuilder#reverse()}. - *

- * - *

- * A {@code null} String returns {@code null}. - *

- * - *
-	 * StringUtils.reverse(null)  = null
-	 * StringUtils.reverse("")    = ""
-	 * StringUtils.reverse("bat") = "tab"
-	 * 
- * - * @param str the String to reverse, may be null - * @return the reversed String, {@code null} if null String input - */ - public static String reverse(final String str) { - if (str == null) { - return null; - } - return new StringBuilder(str).reverse().toString(); - } - - /** - *

- * Reverses a String that is delimited by a specific character. - *

- * - *

- * The Strings between the delimiters are not reversed. Thus java.lang.String - * becomes String.lang.java (if the delimiter is {@code '.'}). - *

- * - *
-	 * StringUtils.reverseDelimited(null, *)      = null
-	 * StringUtils.reverseDelimited("", *)        = ""
-	 * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
-	 * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
-	 * 
- * - * @param str the String to reverse, may be null - * @param separatorChar the separator character to use - * @return the reversed String, {@code null} if null String input - * @since 2.0 - */ - public static String reverseDelimited(final String str, final char separatorChar) { - if (str == null) { - return null; - } - // could implement manually, but simple way is to reuse other, - // probably slower, methods. - /* - * final String[] strs = split(str, separatorChar); ArrayUtils.reverse(strs); - * return join(strs, separatorChar); - */ - throw new UnsupportedOperationException("Not supported in TeaVM"); - } - - /** - *

- * Gets the rightmost {@code len} characters of a String. - *

- * - *

- * If {@code len} characters are not available, or the String is {@code null}, - * the String will be returned without an an exception. An empty String is - * returned if len is negative. - *

- * - *
-	 * StringUtils.right(null, *)    = null
-	 * StringUtils.right(*, -ve)     = ""
-	 * StringUtils.right("", *)      = ""
-	 * StringUtils.right("abc", 0)   = ""
-	 * StringUtils.right("abc", 2)   = "bc"
-	 * StringUtils.right("abc", 4)   = "abc"
-	 * 
- * - * @param str the String to get the rightmost characters from, may be null - * @param len the length of the required String - * @return the rightmost characters, {@code null} if null String input - */ - public static String right(final String str, final int len) { - if (str == null) { - return null; - } - if (len < 0) { - return EMPTY; - } - if (str.length() <= len) { - return str; - } - return str.substring(str.length() - len); - } - - /** - *

- * Right pad a String with spaces (' '). - *

- * - *

- * The String is padded to the size of {@code size}. - *

- * - *
-	 * StringUtils.rightPad(null, *)   = null
-	 * StringUtils.rightPad("", 3)     = "   "
-	 * StringUtils.rightPad("bat", 3)  = "bat"
-	 * StringUtils.rightPad("bat", 5)  = "bat  "
-	 * StringUtils.rightPad("bat", 1)  = "bat"
-	 * StringUtils.rightPad("bat", -1) = "bat"
-	 * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @return right padded String or original String if no padding is necessary, - * {@code null} if null String input - */ - public static String rightPad(final String str, final int size) { - return rightPad(str, size, ' '); - } - - /** - *

- * Right pad a String with a specified character. - *

- * - *

- * The String is padded to the size of {@code size}. - *

- * - *
-	 * StringUtils.rightPad(null, *, *)     = null
-	 * StringUtils.rightPad("", 3, 'z')     = "zzz"
-	 * StringUtils.rightPad("bat", 3, 'z')  = "bat"
-	 * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
-	 * StringUtils.rightPad("bat", 1, 'z')  = "bat"
-	 * StringUtils.rightPad("bat", -1, 'z') = "bat"
-	 * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @param padChar the character to pad with - * @return right padded String or original String if no padding is necessary, - * {@code null} if null String input - * @since 2.0 - */ - public static String rightPad(final String str, final int size, final char padChar) { - if (str == null) { - return null; - } - final int pads = size - str.length(); - if (pads <= 0) { - return str; // returns original String when possible - } - if (pads > PAD_LIMIT) { - return rightPad(str, size, String.valueOf(padChar)); - } - return str.concat(repeat(padChar, pads)); - } - - /** - *

- * Right pad a String with a specified String. - *

- * - *

- * The String is padded to the size of {@code size}. - *

- * - *
-	 * StringUtils.rightPad(null, *, *)      = null
-	 * StringUtils.rightPad("", 3, "z")      = "zzz"
-	 * StringUtils.rightPad("bat", 3, "yz")  = "bat"
-	 * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
-	 * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
-	 * StringUtils.rightPad("bat", 1, "yz")  = "bat"
-	 * StringUtils.rightPad("bat", -1, "yz") = "bat"
-	 * StringUtils.rightPad("bat", 5, null)  = "bat  "
-	 * StringUtils.rightPad("bat", 5, "")    = "bat  "
-	 * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @param padStr the String to pad with, null or empty treated as single space - * @return right padded String or original String if no padding is necessary, - * {@code null} if null String input - */ - public static String rightPad(final String str, final int size, String padStr) { - if (str == null) { - return null; - } - if (isEmpty(padStr)) { - padStr = SPACE; - } - final int padLen = padStr.length(); - final int strLen = str.length(); - final int pads = size - strLen; - if (pads <= 0) { - return str; // returns original String when possible - } - if (padLen == 1 && pads <= PAD_LIMIT) { - return rightPad(str, size, padStr.charAt(0)); - } - - if (pads == padLen) { - return str.concat(padStr); - } else if (pads < padLen) { - return str.concat(padStr.substring(0, pads)); - } else { - final char[] padding = new char[pads]; - final char[] padChars = padStr.toCharArray(); - for (int i = 0; i < pads; i++) { - padding[i] = padChars[i % padLen]; - } - return str.concat(new String(padding)); - } - } - - /** - *

- * Rotate (circular shift) a String of {@code shift} characters. - *

- *
    - *
  • If {@code shift > 0}, right circular shift (ex : ABCDEF => - * FABCDE)
  • - *
  • If {@code shift < 0}, left circular shift (ex : ABCDEF => BCDEFA)
  • - *
- * - *
-	 * StringUtils.rotate(null, *)        = null
-	 * StringUtils.rotate("", *)          = ""
-	 * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
-	 * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
-	 * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
-	 * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
-	 * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
-	 * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
-	 * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
-	 * 
- * - * @param str the String to rotate, may be null - * @param shift number of time to shift (positive : right shift, negative : left - * shift) - * @return the rotated String, or the original String if {@code shift == 0}, or - * {@code null} if null String input - * @since 3.5 - */ - public static String rotate(final String str, final int shift) { - if (str == null) { - return null; - } - - final int strLen = str.length(); - if (shift == 0 || strLen == 0 || shift % strLen == 0) { - return str; - } - - final StringBuilder builder = new StringBuilder(strLen); - final int offset = -(shift % strLen); - builder.append(substring(str, offset)); - builder.append(substring(str, 0, offset)); - return builder.toString(); - } - - /** - *

- * Splits the provided text into an array, using whitespace as the separator. - * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *

- * The separator is not included in the returned String array. Adjacent - * separators are treated as one separator. For more control over the split use - * the StrTokenizer class. - *

- * - *

- * A {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.split(null)       = null
-	 * StringUtils.split("")         = []
-	 * StringUtils.split("abc def")  = ["abc", "def"]
-	 * StringUtils.split("abc  def") = ["abc", "def"]
-	 * StringUtils.split(" abc ")    = ["abc"]
-	 * 
- * - * @param str the String to parse, may be null - * @return an array of parsed Strings, {@code null} if null String input - */ - public static String[] split(final String str) { - return split(str, null, -1); - } - - /** - *

- * Splits the provided text into an array, separator specified. This is an - * alternative to using StringTokenizer. - *

- * - *

- * The separator is not included in the returned String array. Adjacent - * separators are treated as one separator. For more control over the split use - * the StrTokenizer class. - *

- * - *

- * A {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.split(null, *)         = null
-	 * StringUtils.split("", *)           = []
-	 * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
-	 * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
-	 * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
-	 * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
-	 * 
- * - * @param str the String to parse, may be null - * @param separatorChar the character used as the delimiter - * @return an array of parsed Strings, {@code null} if null String input - * @since 2.0 - */ - public static String[] split(final String str, final char separatorChar) { - return splitWorker(str, separatorChar, false); - } - - /** - *

- * Splits the provided text into an array, separators specified. This is an - * alternative to using StringTokenizer. - *

- * - *

- * The separator is not included in the returned String array. Adjacent - * separators are treated as one separator. For more control over the split use - * the StrTokenizer class. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} - * separatorChars splits on whitespace. - *

- * - *
-	 * StringUtils.split(null, *)         = null
-	 * StringUtils.split("", *)           = []
-	 * StringUtils.split("abc def", null) = ["abc", "def"]
-	 * StringUtils.split("abc def", " ")  = ["abc", "def"]
-	 * StringUtils.split("abc  def", " ") = ["abc", "def"]
-	 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
-	 * 
- * - * @param str the String to parse, may be null - * @param separatorChars the characters used as the delimiters, {@code null} - * splits on whitespace - * @return an array of parsed Strings, {@code null} if null String input - */ - public static String[] split(final String str, final String separatorChars) { - return splitWorker(str, separatorChars, -1, false); - } - - /** - *

- * Splits the provided text into an array with a maximum length, separators - * specified. - *

- * - *

- * The separator is not included in the returned String array. Adjacent - * separators are treated as one separator. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} - * separatorChars splits on whitespace. - *

- * - *

- * If more than {@code max} delimited substrings are found, the last returned - * string includes all characters after the first {@code max - 1} returned - * strings (including separator characters). - *

- * - *
-	 * StringUtils.split(null, *, *)            = null
-	 * StringUtils.split("", *, *)              = []
-	 * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
-	 * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
-	 * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
-	 * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
-	 * 
- * - * @param str the String to parse, may be null - * @param separatorChars the characters used as the delimiters, {@code null} - * splits on whitespace - * @param max the maximum number of elements to include in the array. - * A zero or negative value implies no limit - * @return an array of parsed Strings, {@code null} if null String input - */ - public static String[] split(final String str, final String separatorChars, final int max) { - return splitWorker(str, separatorChars, max, false); - } - - /** - *

- * Splits a String by Character type as returned by - * {@code java.lang.Character.getType(char)}. Groups of contiguous characters of - * the same type are returned as complete tokens. - * - *

-	 * StringUtils.splitByCharacterType(null)         = null
-	 * StringUtils.splitByCharacterType("")           = []
-	 * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
-	 * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
-	 * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
-	 * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
-	 * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
-	 * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
-	 * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
-	 * 
- * - * @param str the String to split, may be {@code null} - * @return an array of parsed Strings, {@code null} if null String input - * @since 2.4 - */ - public static String[] splitByCharacterType(final String str) { - return splitByCharacterType(str, false); - } - - /** - *

- * Splits a String by Character type as returned by - * {@code java.lang.Character.getType(char)}. Groups of contiguous characters of - * the same type are returned as complete tokens, with the following exception: - * if {@code camelCase} is {@code true}, the character of type - * {@code Character.UPPERCASE_LETTER}, if any, immediately preceding a token of - * type {@code Character.LOWERCASE_LETTER} will belong to the following token - * rather than to the preceding, if any, {@code Character.UPPERCASE_LETTER} - * token. - * - * @param str the String to split, may be {@code null} - * @param camelCase whether to use so-called "camel-case" for letter types - * @return an array of parsed Strings, {@code null} if null String input - * @since 2.4 - */ - private static String[] splitByCharacterType(final String str, final boolean camelCase) { - if (str == null) { - return null; - } - if (str.isEmpty()) { - return new String[0]; - } - final char[] c = str.toCharArray(); - final List list = new ArrayList<>(); - int tokenStart = 0; - int currentType = Character.getType(c[tokenStart]); - for (int pos = tokenStart + 1; pos < c.length; pos++) { - final int type = Character.getType(c[pos]); - if (type == currentType) { - continue; - } - if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) { - final int newTokenStart = pos - 1; - if (newTokenStart != tokenStart) { - list.add(new String(c, tokenStart, newTokenStart - tokenStart)); - tokenStart = newTokenStart; - } - } else { - list.add(new String(c, tokenStart, pos - tokenStart)); - tokenStart = pos; - } - currentType = type; - } - list.add(new String(c, tokenStart, c.length - tokenStart)); - return list.toArray(new String[0]); - } - - /** - *

- * Splits a String by Character type as returned by - * {@code java.lang.Character.getType(char)}. Groups of contiguous characters of - * the same type are returned as complete tokens, with the following exception: - * the character of type {@code Character.UPPERCASE_LETTER}, if any, immediately - * preceding a token of type {@code Character.LOWERCASE_LETTER} will belong to - * the following token rather than to the preceding, if any, - * {@code Character.UPPERCASE_LETTER} token. - * - *

-	 * StringUtils.splitByCharacterTypeCamelCase(null)         = null
-	 * StringUtils.splitByCharacterTypeCamelCase("")           = []
-	 * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
-	 * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
-	 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
-	 * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
-	 * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
-	 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
-	 * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
-	 * 
- * - * @param str the String to split, may be {@code null} - * @return an array of parsed Strings, {@code null} if null String input - * @since 2.4 - */ - public static String[] splitByCharacterTypeCamelCase(final String str) { - return splitByCharacterType(str, true); - } - - /** - *

- * Splits the provided text into an array, separator string specified. - *

- * - *

- * The separator(s) will not be included in the returned String array. Adjacent - * separators are treated as one separator. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} separator - * splits on whitespace. - *

- * - *
-	 * StringUtils.splitByWholeSeparator(null, *)               = null
-	 * StringUtils.splitByWholeSeparator("", *)                 = []
-	 * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
-	 * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
-	 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
-	 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
-	 * 
- * - * @param str the String to parse, may be null - * @param separator String containing the String to be used as a delimiter, - * {@code null} splits on whitespace - * @return an array of parsed Strings, {@code null} if null String was input - */ - public static String[] splitByWholeSeparator(final String str, final String separator) { - return splitByWholeSeparatorWorker(str, separator, -1, false); - } - - /** - *

- * Splits the provided text into an array, separator string specified. Returns a - * maximum of {@code max} substrings. - *

- * - *

- * The separator(s) will not be included in the returned String array. Adjacent - * separators are treated as one separator. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} separator - * splits on whitespace. - *

- * - *
-	 * StringUtils.splitByWholeSeparator(null, *, *)               = null
-	 * StringUtils.splitByWholeSeparator("", *, *)                 = []
-	 * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
-	 * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
-	 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
-	 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
-	 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
-	 * 
- * - * @param str the String to parse, may be null - * @param separator String containing the String to be used as a delimiter, - * {@code null} splits on whitespace - * @param max the maximum number of elements to include in the returned - * array. A zero or negative value implies no limit. - * @return an array of parsed Strings, {@code null} if null String was input - */ - public static String[] splitByWholeSeparator(final String str, final String separator, final int max) { - return splitByWholeSeparatorWorker(str, separator, max, false); - } - - /** - *

- * Splits the provided text into an array, separator string specified. - *

- * - *

- * The separator is not included in the returned String array. Adjacent - * separators are treated as separators for empty tokens. For more control over - * the split use the StrTokenizer class. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} separator - * splits on whitespace. - *

- * - *
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
-	 * 
- * - * @param str the String to parse, may be null - * @param separator String containing the String to be used as a delimiter, - * {@code null} splits on whitespace - * @return an array of parsed Strings, {@code null} if null String was input - * @since 2.4 - */ - public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) { - return splitByWholeSeparatorWorker(str, separator, -1, true); - } - - /** - *

- * Splits the provided text into an array, separator string specified. Returns a - * maximum of {@code max} substrings. - *

- * - *

- * The separator is not included in the returned String array. Adjacent - * separators are treated as separators for empty tokens. For more control over - * the split use the StrTokenizer class. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} separator - * splits on whitespace. - *

- * - *
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
-	 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
-	 * 
- * - * @param str the String to parse, may be null - * @param separator String containing the String to be used as a delimiter, - * {@code null} splits on whitespace - * @param max the maximum number of elements to include in the returned - * array. A zero or negative value implies no limit. - * @return an array of parsed Strings, {@code null} if null String was input - * @since 2.4 - */ - public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, - final int max) { - return splitByWholeSeparatorWorker(str, separator, max, true); - } - - /** - * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} - * methods. - * - * @param str the String to parse, may be {@code null} - * @param separator String containing the String to be used as a - * delimiter, {@code null} splits on whitespace - * @param max the maximum number of elements to include in the - * returned array. A zero or negative value implies no - * limit. - * @param preserveAllTokens if {@code true}, adjacent separators are treated as - * empty token separators; if {@code false}, adjacent - * separators are treated as one separator. - * @return an array of parsed Strings, {@code null} if null String input - * @since 2.4 - */ - private static String[] splitByWholeSeparatorWorker(final String str, final String separator, final int max, - final boolean preserveAllTokens) { - if (str == null) { - return null; - } - - final int len = str.length(); - - if (len == 0) { - return new String[0]; - } - - if (separator == null || EMPTY.equals(separator)) { - // Split on whitespace. - return splitWorker(str, null, max, preserveAllTokens); - } - - final int separatorLength = separator.length(); - - final ArrayList substrings = new ArrayList<>(); - int numberOfSubstrings = 0; - int beg = 0; - int end = 0; - while (end < len) { - end = str.indexOf(separator, beg); - - if (end > -1) { - if (end > beg) { - numberOfSubstrings += 1; - - if (numberOfSubstrings == max) { - end = len; - substrings.add(str.substring(beg)); - } else { - // The following is OK, because String.substring( beg, end ) excludes - // the character at the position 'end'. - substrings.add(str.substring(beg, end)); - - // Set the starting point for the next search. - // The following is equivalent to beg = end + (separatorLength - 1) + 1, - // which is the right calculation: - beg = end + separatorLength; - } - } else { - // We found a consecutive occurrence of the separator, so skip it. - if (preserveAllTokens) { - numberOfSubstrings += 1; - if (numberOfSubstrings == max) { - end = len; - substrings.add(str.substring(beg)); - } else { - substrings.add(EMPTY); - } - } - beg = end + separatorLength; - } - } else { - // String.substring( beg ) goes from 'beg' to the end of the String. - substrings.add(str.substring(beg)); - end = len; - } - } - - return substrings.toArray(new String[0]); - } - - /** - *

- * Splits the provided text into an array, using whitespace as the separator, - * preserving all tokens, including empty tokens created by adjacent separators. - * This is an alternative to using StringTokenizer. Whitespace is defined by - * {@link Character#isWhitespace(char)}. - *

- * - *

- * The separator is not included in the returned String array. Adjacent - * separators are treated as separators for empty tokens. For more control over - * the split use the StrTokenizer class. - *

- * - *

- * A {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.splitPreserveAllTokens(null)       = null
-	 * StringUtils.splitPreserveAllTokens("")         = []
-	 * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
-	 * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
-	 * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
-	 * 
- * - * @param str the String to parse, may be {@code null} - * @return an array of parsed Strings, {@code null} if null String input - * @since 2.1 - */ - public static String[] splitPreserveAllTokens(final String str) { - return splitWorker(str, null, -1, true); - } - - /** - *

- * Splits the provided text into an array, separator specified, preserving all - * tokens, including empty tokens created by adjacent separators. This is an - * alternative to using StringTokenizer. - *

- * - *

- * The separator is not included in the returned String array. Adjacent - * separators are treated as separators for empty tokens. For more control over - * the split use the StrTokenizer class. - *

- * - *

- * A {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.splitPreserveAllTokens(null, *)         = null
-	 * StringUtils.splitPreserveAllTokens("", *)           = []
-	 * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
-	 * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
-	 * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
-	 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
-	 * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
-	 * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
-	 * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
-	 * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
-	 * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
-	 * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
-	 * 
- * - * @param str the String to parse, may be {@code null} - * @param separatorChar the character used as the delimiter, {@code null} splits - * on whitespace - * @return an array of parsed Strings, {@code null} if null String input - * @since 2.1 - */ - public static String[] splitPreserveAllTokens(final String str, final char separatorChar) { - return splitWorker(str, separatorChar, true); - } - - /** - *

- * Splits the provided text into an array, separators specified, preserving all - * tokens, including empty tokens created by adjacent separators. This is an - * alternative to using StringTokenizer. - *

- * - *

- * The separator is not included in the returned String array. Adjacent - * separators are treated as separators for empty tokens. For more control over - * the split use the StrTokenizer class. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} - * separatorChars splits on whitespace. - *

- * - *
-	 * StringUtils.splitPreserveAllTokens(null, *)           = null
-	 * StringUtils.splitPreserveAllTokens("", *)             = []
-	 * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
-	 * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
-	 * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
-	 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
-	 * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
-	 * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
-	 * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
-	 * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
-	 * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
-	 * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
-	 * 
- * - * @param str the String to parse, may be {@code null} - * @param separatorChars the characters used as the delimiters, {@code null} - * splits on whitespace - * @return an array of parsed Strings, {@code null} if null String input - * @since 2.1 - */ - public static String[] splitPreserveAllTokens(final String str, final String separatorChars) { - return splitWorker(str, separatorChars, -1, true); - } - - /** - *

- * Splits the provided text into an array with a maximum length, separators - * specified, preserving all tokens, including empty tokens created by adjacent - * separators. - *

- * - *

- * The separator is not included in the returned String array. Adjacent - * separators are treated as separators for empty tokens. Adjacent separators - * are treated as one separator. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} - * separatorChars splits on whitespace. - *

- * - *

- * If more than {@code max} delimited substrings are found, the last returned - * string includes all characters after the first {@code max - 1} returned - * strings (including separator characters). - *

- * - *
-	 * StringUtils.splitPreserveAllTokens(null, *, *)            = null
-	 * StringUtils.splitPreserveAllTokens("", *, *)              = []
-	 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
-	 * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
-	 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
-	 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
-	 * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
-	 * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
-	 * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
-	 * 
- * - * @param str the String to parse, may be {@code null} - * @param separatorChars the characters used as the delimiters, {@code null} - * splits on whitespace - * @param max the maximum number of elements to include in the array. - * A zero or negative value implies no limit - * @return an array of parsed Strings, {@code null} if null String input - * @since 2.1 - */ - public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) { - return splitWorker(str, separatorChars, max, true); - } - - /** - * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} - * methods that do not return a maximum array length. - * - * @param str the String to parse, may be {@code null} - * @param separatorChar the separate character - * @param preserveAllTokens if {@code true}, adjacent separators are treated as - * empty token separators; if {@code false}, adjacent - * separators are treated as one separator. - * @return an array of parsed Strings, {@code null} if null String input - */ - private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) { - // Performance tuned for 2.0 (JDK1.4) - - if (str == null) { - return null; - } - final int len = str.length(); - if (len == 0) { - return new String[0]; - } - final List list = new ArrayList<>(); - int i = 0; - int start = 0; - boolean match = false; - boolean lastMatch = false; - while (i < len) { - if (str.charAt(i) == separatorChar) { - if (match || preserveAllTokens) { - list.add(str.substring(start, i)); - match = false; - lastMatch = true; - } - start = ++i; - continue; - } - lastMatch = false; - match = true; - i++; - } - if (match || preserveAllTokens && lastMatch) { - list.add(str.substring(start, i)); - } - return list.toArray(new String[0]); - } - - /** - * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} - * methods that return a maximum array length. - * - * @param str the String to parse, may be {@code null} - * @param separatorChars the separate character - * @param max the maximum number of elements to include in the - * array. A zero or negative value implies no limit. - * @param preserveAllTokens if {@code true}, adjacent separators are treated as - * empty token separators; if {@code false}, adjacent - * separators are treated as one separator. - * @return an array of parsed Strings, {@code null} if null String input - */ - private static String[] splitWorker(final String str, final String separatorChars, final int max, - final boolean preserveAllTokens) { - // Performance tuned for 2.0 (JDK1.4) - // Direct code is quicker than StringTokenizer. - // Also, StringTokenizer uses isSpace() not isWhitespace() - - if (str == null) { - return null; - } - final int len = str.length(); - if (len == 0) { - return new String[0]; - } - final List list = new ArrayList<>(); - int sizePlus1 = 1; - int i = 0; - int start = 0; - boolean match = false; - boolean lastMatch = false; - if (separatorChars == null) { - // Null separator means use whitespace - while (i < len) { - if (Character.isWhitespace(str.charAt(i))) { - if (match || preserveAllTokens) { - lastMatch = true; - if (sizePlus1++ == max) { - i = len; - lastMatch = false; - } - list.add(str.substring(start, i)); - match = false; - } - start = ++i; - continue; - } - lastMatch = false; - match = true; - i++; - } - } else if (separatorChars.length() == 1) { - // Optimise 1 character case - final char sep = separatorChars.charAt(0); - while (i < len) { - if (str.charAt(i) == sep) { - if (match || preserveAllTokens) { - lastMatch = true; - if (sizePlus1++ == max) { - i = len; - lastMatch = false; - } - list.add(str.substring(start, i)); - match = false; - } - start = ++i; - continue; - } - lastMatch = false; - match = true; - i++; - } - } else { - // standard case - while (i < len) { - if (separatorChars.indexOf(str.charAt(i)) >= 0) { - if (match || preserveAllTokens) { - lastMatch = true; - if (sizePlus1++ == max) { - i = len; - lastMatch = false; - } - list.add(str.substring(start, i)); - match = false; - } - start = ++i; - continue; - } - lastMatch = false; - match = true; - i++; - } - } - if (match || preserveAllTokens && lastMatch) { - list.add(str.substring(start, i)); - } - return list.toArray(new String[0]); - } - - /** - *

- * Check if a CharSequence starts with a specified prefix. - *

- * - *

- * {@code null}s are handled without exceptions. Two {@code null} references are - * considered to be equal. The comparison is case sensitive. - *

- * - *
-	 * StringUtils.startsWith(null, null)      = true
-	 * StringUtils.startsWith(null, "abc")     = false
-	 * StringUtils.startsWith("abcdef", null)  = false
-	 * StringUtils.startsWith("abcdef", "abc") = true
-	 * StringUtils.startsWith("ABCDEF", "abc") = false
-	 * 
- * - * @see java.lang.String#startsWith(String) - * @param str the CharSequence to check, may be null - * @param prefix the prefix to find, may be null - * @return {@code true} if the CharSequence starts with the prefix, case - * sensitive, or both {@code null} - * @since 2.4 - * @since 3.0 Changed signature from startsWith(String, String) to - * startsWith(CharSequence, CharSequence) - */ - public static boolean startsWith(final CharSequence str, final CharSequence prefix) { - return startsWith(str, prefix, false); - } - - /** - *

- * Check if a CharSequence starts with a specified prefix (optionally case - * insensitive). - *

- * - * @see java.lang.String#startsWith(String) - * @param str the CharSequence to check, may be null - * @param prefix the prefix to find, may be null - * @param ignoreCase indicates whether the compare should ignore case (case - * insensitive) or not. - * @return {@code true} if the CharSequence starts with the prefix or both - * {@code null} - */ - private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) { - if (str == null || prefix == null) { - return str == prefix; - } - // Get length once instead of twice in the unlikely case that it changes. - final int preLen = prefix.length(); - if (preLen > str.length()) { - return false; - } - return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, preLen); - } - - /** - *

- * Check if a CharSequence starts with any of the provided case-sensitive - * prefixes. - *

- * - *
-	 * StringUtils.startsWithAny(null, null)      = false
-	 * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
-	 * StringUtils.startsWithAny("abcxyz", null)     = false
-	 * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
-	 * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
-	 * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
-	 * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
-	 * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
-	 * 
- * - * @param sequence the CharSequence to check, may be null - * @param searchStrings the case-sensitive CharSequence prefixes, may be empty - * or contain {@code null} - * @see StringUtils#startsWith(CharSequence, CharSequence) - * @return {@code true} if the input {@code sequence} is {@code null} AND no - * {@code searchStrings} are provided, or the input {@code sequence} - * begins with any of the provided case-sensitive {@code searchStrings}. - * @since 2.5 - * @since 3.0 Changed signature from startsWithAny(String, String[]) to - * startsWithAny(CharSequence, CharSequence...) - */ - public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { - if (isEmpty(sequence) || searchStrings.length == 0) { - return false; - } - for (final CharSequence searchString : searchStrings) { - if (startsWith(sequence, searchString)) { - return true; - } - } - return false; - } - - /** - *

- * Case insensitive check if a CharSequence starts with a specified prefix. - *

- * - *

- * {@code null}s are handled without exceptions. Two {@code null} references are - * considered to be equal. The comparison is case insensitive. - *

- * - *
-	 * StringUtils.startsWithIgnoreCase(null, null)      = true
-	 * StringUtils.startsWithIgnoreCase(null, "abc")     = false
-	 * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
-	 * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
-	 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
-	 * 
- * - * @see java.lang.String#startsWith(String) - * @param str the CharSequence to check, may be null - * @param prefix the prefix to find, may be null - * @return {@code true} if the CharSequence starts with the prefix, case - * insensitive, or both {@code null} - * @since 2.4 - * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to - * startsWithIgnoreCase(CharSequence, CharSequence) - */ - public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) { - return startsWith(str, prefix, true); - } - - /** - *

- * Strips whitespace from the start and end of a String. - *

- * - *

- * This is similar to {@link #trim(String)} but removes whitespace. Whitespace - * is defined by {@link Character#isWhitespace(char)}. - *

- * - *

- * A {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.strip(null)     = null
-	 * StringUtils.strip("")       = ""
-	 * StringUtils.strip("   ")    = ""
-	 * StringUtils.strip("abc")    = "abc"
-	 * StringUtils.strip("  abc")  = "abc"
-	 * StringUtils.strip("abc  ")  = "abc"
-	 * StringUtils.strip(" abc ")  = "abc"
-	 * StringUtils.strip(" ab c ") = "ab c"
-	 * 
- * - * @param str the String to remove whitespace from, may be null - * @return the stripped String, {@code null} if null String input - */ - public static String strip(final String str) { - return strip(str, null); - } - - /** - *

- * Strips any of a set of characters from the start and end of a String. This is - * similar to {@link String#trim()} but allows the characters to be stripped to - * be controlled. - *

- * - *

- * A {@code null} input String returns {@code null}. An empty string ("") input - * returns the empty string. - *

- * - *

- * If the stripChars String is {@code null}, whitespace is stripped as defined - * by {@link Character#isWhitespace(char)}. Alternatively use - * {@link #strip(String)}. - *

- * - *
-	 * StringUtils.strip(null, *)          = null
-	 * StringUtils.strip("", *)            = ""
-	 * StringUtils.strip("abc", null)      = "abc"
-	 * StringUtils.strip("  abc", null)    = "abc"
-	 * StringUtils.strip("abc  ", null)    = "abc"
-	 * StringUtils.strip(" abc ", null)    = "abc"
-	 * StringUtils.strip("  abcyx", "xyz") = "  abc"
-	 * 
- * - * @param str the String to remove characters from, may be null - * @param stripChars the characters to remove, null treated as whitespace - * @return the stripped String, {@code null} if null String input - */ - public static String strip(String str, final String stripChars) { - str = stripStart(str, stripChars); - return stripEnd(str, stripChars); - } - - /** - *

- * Removes diacritics (~= accents) from a string. The case will not be altered. - *

- *

- * For instance, 'à' will be replaced by 'a'. - *

- *

- * Note that ligatures will be left as is. - *

- * - *
-	 * StringUtils.stripAccents(null)                = null
-	 * StringUtils.stripAccents("")                  = ""
-	 * StringUtils.stripAccents("control")           = "control"
-	 * StringUtils.stripAccents("éclair")     = "eclair"
-	 * 
- * - * @param input String to be stripped - * @return input text with diacritics removed - * - * @since 3.0 - */ - // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented - // characters by their unaccented equivalent (and uncommitted bug fix: - // https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907). - public static String stripAccents(final String input) { - if (input == null) { - return null; - } - final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD)); - convertRemainingAccentCharacters(decomposed); - // Note that this doesn't correctly remove ligatures... - return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY); - } - - /** - *

- * Strips whitespace from the start and end of every String in an array. - * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *

- * A new array is returned each time, except for length zero. A {@code null} - * array will return {@code null}. An empty array will return itself. A - * {@code null} array entry will be ignored. - *

- * - *
-	 * StringUtils.stripAll(null)             = null
-	 * StringUtils.stripAll([])               = []
-	 * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
-	 * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
-	 * 
- * - * @param strs the array to remove whitespace from, may be null - * @return the stripped Strings, {@code null} if null array input - */ - public static String[] stripAll(final String... strs) { - return stripAll(strs, null); - } - - /** - *

- * Strips any of a set of characters from the start and end of every String in - * an array. - *

- *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *

- * A new array is returned each time, except for length zero. A {@code null} - * array will return {@code null}. An empty array will return itself. A - * {@code null} array entry will be ignored. A {@code null} stripChars will - * strip whitespace as defined by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.stripAll(null, *)                = null
-	 * StringUtils.stripAll([], *)                  = []
-	 * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
-	 * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
-	 * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
-	 * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
-	 * 
- * - * @param strs the array to remove characters from, may be null - * @param stripChars the characters to remove, null treated as whitespace - * @return the stripped Strings, {@code null} if null array input - */ - public static String[] stripAll(final String[] strs, final String stripChars) { - final int strsLen = strs.length; - if (strsLen == 0) { - return strs; - } - final String[] newArr = new String[strsLen]; - for (int i = 0; i < strsLen; i++) { - newArr[i] = strip(strs[i], stripChars); - } - return newArr; - } - - /** - *

- * Strips any of a set of characters from the end of a String. - *

- * - *

- * A {@code null} input String returns {@code null}. An empty string ("") input - * returns the empty string. - *

- * - *

- * If the stripChars String is {@code null}, whitespace is stripped as defined - * by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.stripEnd(null, *)          = null
-	 * StringUtils.stripEnd("", *)            = ""
-	 * StringUtils.stripEnd("abc", "")        = "abc"
-	 * StringUtils.stripEnd("abc", null)      = "abc"
-	 * StringUtils.stripEnd("  abc", null)    = "  abc"
-	 * StringUtils.stripEnd("abc  ", null)    = "abc"
-	 * StringUtils.stripEnd(" abc ", null)    = " abc"
-	 * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
-	 * StringUtils.stripEnd("120.00", ".0")   = "12"
-	 * 
- * - * @param str the String to remove characters from, may be null - * @param stripChars the set of characters to remove, null treated as whitespace - * @return the stripped String, {@code null} if null String input - */ - public static String stripEnd(final String str, final String stripChars) { - int end = length(str); - if (end == 0) { - return str; - } - - if (stripChars == null) { - while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { - end--; - } - } else if (stripChars.isEmpty()) { - return str; - } else { - while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) { - end--; - } - } - return str.substring(0, end); - } - - /** - *

- * Strips any of a set of characters from the start of a String. - *

- * - *

- * A {@code null} input String returns {@code null}. An empty string ("") input - * returns the empty string. - *

- * - *

- * If the stripChars String is {@code null}, whitespace is stripped as defined - * by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.stripStart(null, *)          = null
-	 * StringUtils.stripStart("", *)            = ""
-	 * StringUtils.stripStart("abc", "")        = "abc"
-	 * StringUtils.stripStart("abc", null)      = "abc"
-	 * StringUtils.stripStart("  abc", null)    = "abc"
-	 * StringUtils.stripStart("abc  ", null)    = "abc  "
-	 * StringUtils.stripStart(" abc ", null)    = "abc "
-	 * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
-	 * 
- * - * @param str the String to remove characters from, may be null - * @param stripChars the characters to remove, null treated as whitespace - * @return the stripped String, {@code null} if null String input - */ - public static String stripStart(final String str, final String stripChars) { - final int strLen = length(str); - if (strLen == 0) { - return str; - } - int start = 0; - if (stripChars == null) { - while (start != strLen && Character.isWhitespace(str.charAt(start))) { - start++; - } - } else if (stripChars.isEmpty()) { - return str; - } else { - while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) { - start++; - } - } - return str.substring(start); - } - - /** - *

- * Strips whitespace from the start and end of a String returning an empty - * String if {@code null} input. - *

- * - *

- * This is similar to {@link #trimToEmpty(String)} but removes whitespace. - * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.stripToEmpty(null)     = ""
-	 * StringUtils.stripToEmpty("")       = ""
-	 * StringUtils.stripToEmpty("   ")    = ""
-	 * StringUtils.stripToEmpty("abc")    = "abc"
-	 * StringUtils.stripToEmpty("  abc")  = "abc"
-	 * StringUtils.stripToEmpty("abc  ")  = "abc"
-	 * StringUtils.stripToEmpty(" abc ")  = "abc"
-	 * StringUtils.stripToEmpty(" ab c ") = "ab c"
-	 * 
- * - * @param str the String to be stripped, may be null - * @return the trimmed String, or an empty String if {@code null} input - * @since 2.0 - */ - public static String stripToEmpty(final String str) { - return str == null ? EMPTY : strip(str, null); - } - - /** - *

- * Strips whitespace from the start and end of a String returning {@code null} - * if the String is empty ("") after the strip. - *

- * - *

- * This is similar to {@link #trimToNull(String)} but removes whitespace. - * Whitespace is defined by {@link Character#isWhitespace(char)}. - *

- * - *
-	 * StringUtils.stripToNull(null)     = null
-	 * StringUtils.stripToNull("")       = null
-	 * StringUtils.stripToNull("   ")    = null
-	 * StringUtils.stripToNull("abc")    = "abc"
-	 * StringUtils.stripToNull("  abc")  = "abc"
-	 * StringUtils.stripToNull("abc  ")  = "abc"
-	 * StringUtils.stripToNull(" abc ")  = "abc"
-	 * StringUtils.stripToNull(" ab c ") = "ab c"
-	 * 
- * - * @param str the String to be stripped, may be null - * @return the stripped String, {@code null} if whitespace, empty or null String - * input - * @since 2.0 - */ - public static String stripToNull(String str) { - if (str == null) { - return null; - } - str = strip(str, null); - return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here - } - - /** - *

- * Gets a substring from the specified String avoiding exceptions. - *

- * - *

- * A negative start position can be used to start {@code n} characters from the - * end of the String. - *

- * - *

- * A {@code null} String will return {@code null}. An empty ("") String will - * return "". - *

- * - *
-	 * StringUtils.substring(null, *)   = null
-	 * StringUtils.substring("", *)     = ""
-	 * StringUtils.substring("abc", 0)  = "abc"
-	 * StringUtils.substring("abc", 2)  = "c"
-	 * StringUtils.substring("abc", 4)  = ""
-	 * StringUtils.substring("abc", -2) = "bc"
-	 * StringUtils.substring("abc", -4) = "abc"
-	 * 
- * - * @param str the String to get the substring from, may be null - * @param start the position to start from, negative means count back from the - * end of the String by this many characters - * @return substring from start position, {@code null} if null String input - */ - public static String substring(final String str, int start) { - if (str == null) { - return null; - } - - // handle negatives, which means last n characters - if (start < 0) { - start = str.length() + start; // remember start is negative - } - - if (start < 0) { - start = 0; - } - if (start > str.length()) { - return EMPTY; - } - - return str.substring(start); - } - - /** - *

- * Gets a substring from the specified String avoiding exceptions. - *

- * - *

- * A negative start position can be used to start/end {@code n} characters from - * the end of the String. - *

- * - *

- * The returned substring starts with the character in the {@code start} - * position and ends before the {@code end} position. All position counting is - * zero-based -- i.e., to start at the beginning of the string use - * {@code start = 0}. Negative start and end positions can be used to specify - * offsets relative to the end of the String. - *

- * - *

- * If {@code start} is not strictly to the left of {@code end}, "" is returned. - *

- * - *
-	 * StringUtils.substring(null, *, *)    = null
-	 * StringUtils.substring("", * ,  *)    = "";
-	 * StringUtils.substring("abc", 0, 2)   = "ab"
-	 * StringUtils.substring("abc", 2, 0)   = ""
-	 * StringUtils.substring("abc", 2, 4)   = "c"
-	 * StringUtils.substring("abc", 4, 6)   = ""
-	 * StringUtils.substring("abc", 2, 2)   = ""
-	 * StringUtils.substring("abc", -2, -1) = "b"
-	 * StringUtils.substring("abc", -4, 2)  = "ab"
-	 * 
- * - * @param str the String to get the substring from, may be null - * @param start the position to start from, negative means count back from the - * end of the String by this many characters - * @param end the position to end at (exclusive), negative means count back - * from the end of the String by this many characters - * @return substring from start position to end position, {@code null} if null - * String input - */ - public static String substring(final String str, int start, int end) { - if (str == null) { - return null; - } - - // handle negatives - if (end < 0) { - end = str.length() + end; // remember end is negative - } - if (start < 0) { - start = str.length() + start; // remember start is negative - } - - // check length next - if (end > str.length()) { - end = str.length(); - } - - // if start is greater than end, return "" - if (start > end) { - return EMPTY; - } - - if (start < 0) { - start = 0; - } - if (end < 0) { - end = 0; - } - - return str.substring(start, end); - } - - /** - *

- * Gets the substring after the first occurrence of a separator. The separator - * is not returned. - *

- * - *

- * A {@code null} string input will return {@code null}. An empty ("") string - * input will return the empty string. - * - *

- * If nothing is found, the empty string is returned. - *

- * - *
-	 * StringUtils.substringAfter(null, *)      = null
-	 * StringUtils.substringAfter("", *)        = ""
-	 * StringUtils.substringAfter("abc", 'a')   = "bc"
-	 * StringUtils.substringAfter("abcba", 'b') = "cba"
-	 * StringUtils.substringAfter("abc", 'c')   = ""
-	 * StringUtils.substringAfter("abc", 'd')   = ""
-	 * StringUtils.substringAfter(" abc", 32)   = "abc"
-	 * 
- * - * @param str the String to get a substring from, may be null - * @param separator the character to search. - * @return the substring after the first occurrence of the separator, - * {@code null} if null String input - * @since 3.11 - */ - public static String substringAfter(final String str, final int separator) { - if (isEmpty(str)) { - return str; - } - final int pos = str.indexOf(separator); - if (pos == INDEX_NOT_FOUND) { - return EMPTY; - } - return str.substring(pos + 1); - } - - /** - *

- * Gets the substring after the first occurrence of a separator. The separator - * is not returned. - *

- * - *

- * A {@code null} string input will return {@code null}. An empty ("") string - * input will return the empty string. A {@code null} separator will return the - * empty string if the input string is not {@code null}. - *

- * - *

- * If nothing is found, the empty string is returned. - *

- * - *
-	 * StringUtils.substringAfter(null, *)      = null
-	 * StringUtils.substringAfter("", *)        = ""
-	 * StringUtils.substringAfter(*, null)      = ""
-	 * StringUtils.substringAfter("abc", "a")   = "bc"
-	 * StringUtils.substringAfter("abcba", "b") = "cba"
-	 * StringUtils.substringAfter("abc", "c")   = ""
-	 * StringUtils.substringAfter("abc", "d")   = ""
-	 * StringUtils.substringAfter("abc", "")    = "abc"
-	 * 
- * - * @param str the String to get a substring from, may be null - * @param separator the String to search for, may be null - * @return the substring after the first occurrence of the separator, - * {@code null} if null String input - * @since 2.0 - */ - public static String substringAfter(final String str, final String separator) { - if (isEmpty(str)) { - return str; - } - if (separator == null) { - return EMPTY; - } - final int pos = str.indexOf(separator); - if (pos == INDEX_NOT_FOUND) { - return EMPTY; - } - return str.substring(pos + separator.length()); - } - - /** - *

- * Gets the substring after the last occurrence of a separator. The separator is - * not returned. - *

- * - *

- * A {@code null} string input will return {@code null}. An empty ("") string - * input will return the empty string. - * - *

- * If nothing is found, the empty string is returned. - *

- * - *
-	 * StringUtils.substringAfterLast(null, *)      = null
-	 * StringUtils.substringAfterLast("", *)        = ""
-	 * StringUtils.substringAfterLast("abc", 'a')   = "bc"
-	 * StringUtils.substringAfterLast(" bc", 32)    = "bc"
-	 * StringUtils.substringAfterLast("abcba", 'b') = "a"
-	 * StringUtils.substringAfterLast("abc", 'c')   = ""
-	 * StringUtils.substringAfterLast("a", 'a')     = ""
-	 * StringUtils.substringAfterLast("a", 'z')     = ""
-	 * 
- * - * @param str the String to get a substring from, may be null - * @param separator the String to search for, may be null - * @return the substring after the last occurrence of the separator, - * {@code null} if null String input - * @since 3.11 - */ - public static String substringAfterLast(final String str, final int separator) { - if (isEmpty(str)) { - return str; - } - final int pos = str.lastIndexOf(separator); - if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) { - return EMPTY; - } - return str.substring(pos + 1); - } - - /** - *

- * Gets the substring after the last occurrence of a separator. The separator is - * not returned. - *

- * - *

- * A {@code null} string input will return {@code null}. An empty ("") string - * input will return the empty string. An empty or {@code null} separator will - * return the empty string if the input string is not {@code null}. - *

- * - *

- * If nothing is found, the empty string is returned. - *

- * - *
-	 * StringUtils.substringAfterLast(null, *)      = null
-	 * StringUtils.substringAfterLast("", *)        = ""
-	 * StringUtils.substringAfterLast(*, "")        = ""
-	 * StringUtils.substringAfterLast(*, null)      = ""
-	 * StringUtils.substringAfterLast("abc", "a")   = "bc"
-	 * StringUtils.substringAfterLast("abcba", "b") = "a"
-	 * StringUtils.substringAfterLast("abc", "c")   = ""
-	 * StringUtils.substringAfterLast("a", "a")     = ""
-	 * StringUtils.substringAfterLast("a", "z")     = ""
-	 * 
- * - * @param str the String to get a substring from, may be null - * @param separator the String to search for, may be null - * @return the substring after the last occurrence of the separator, - * {@code null} if null String input - * @since 2.0 - */ - public static String substringAfterLast(final String str, final String separator) { - if (isEmpty(str)) { - return str; - } - if (isEmpty(separator)) { - return EMPTY; - } - final int pos = str.lastIndexOf(separator); - if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) { - return EMPTY; - } - return str.substring(pos + separator.length()); - } - - /** - *

- * Gets the substring before the first occurrence of a separator. The separator - * is not returned. - *

- * - *

- * A {@code null} string input will return {@code null}. An empty ("") string - * input will return the empty string. - *

- * - *

- * If nothing is found, the string input is returned. - *

- * - *
-	 * StringUtils.substringBefore(null, *)      = null
-	 * StringUtils.substringBefore("", *)        = ""
-	 * StringUtils.substringBefore("abc", 'a')   = ""
-	 * StringUtils.substringBefore("abcba", 'b') = "a"
-	 * StringUtils.substringBefore("abc", 'c')   = "ab"
-	 * StringUtils.substringBefore("abc", 'd')   = "abc"
-	 * 
- * - * @param str the String to get a substring from, may be null - * @param separator the String to search for, may be null - * @return the substring before the first occurrence of the separator, - * {@code null} if null String input - * @since 3.12.0 - */ - public static String substringBefore(final String str, final int separator) { - if (isEmpty(str)) { - return str; - } - final int pos = str.indexOf(separator); - if (pos == INDEX_NOT_FOUND) { - return str; - } - return str.substring(0, pos); - } - - /** - *

- * Gets the substring before the first occurrence of a separator. The separator - * is not returned. - *

- * - *

- * A {@code null} string input will return {@code null}. An empty ("") string - * input will return the empty string. A {@code null} separator will return the - * input string. - *

- * - *

- * If nothing is found, the string input is returned. - *

- * - *
-	 * StringUtils.substringBefore(null, *)      = null
-	 * StringUtils.substringBefore("", *)        = ""
-	 * StringUtils.substringBefore("abc", "a")   = ""
-	 * StringUtils.substringBefore("abcba", "b") = "a"
-	 * StringUtils.substringBefore("abc", "c")   = "ab"
-	 * StringUtils.substringBefore("abc", "d")   = "abc"
-	 * StringUtils.substringBefore("abc", "")    = ""
-	 * StringUtils.substringBefore("abc", null)  = "abc"
-	 * 
- * - * @param str the String to get a substring from, may be null - * @param separator the String to search for, may be null - * @return the substring before the first occurrence of the separator, - * {@code null} if null String input - * @since 2.0 - */ - public static String substringBefore(final String str, final String separator) { - if (isEmpty(str) || separator == null) { - return str; - } - if (separator.isEmpty()) { - return EMPTY; - } - final int pos = str.indexOf(separator); - if (pos == INDEX_NOT_FOUND) { - return str; - } - return str.substring(0, pos); - } - - /** - *

- * Gets the substring before the last occurrence of a separator. The separator - * is not returned. - *

- * - *

- * A {@code null} string input will return {@code null}. An empty ("") string - * input will return the empty string. An empty or {@code null} separator will - * return the input string. - *

- * - *

- * If nothing is found, the string input is returned. - *

- * - *
-	 * StringUtils.substringBeforeLast(null, *)      = null
-	 * StringUtils.substringBeforeLast("", *)        = ""
-	 * StringUtils.substringBeforeLast("abcba", "b") = "abc"
-	 * StringUtils.substringBeforeLast("abc", "c")   = "ab"
-	 * StringUtils.substringBeforeLast("a", "a")     = ""
-	 * StringUtils.substringBeforeLast("a", "z")     = "a"
-	 * StringUtils.substringBeforeLast("a", null)    = "a"
-	 * StringUtils.substringBeforeLast("a", "")      = "a"
-	 * 
- * - * @param str the String to get a substring from, may be null - * @param separator the String to search for, may be null - * @return the substring before the last occurrence of the separator, - * {@code null} if null String input - * @since 2.0 - */ - public static String substringBeforeLast(final String str, final String separator) { - if (isEmpty(str) || isEmpty(separator)) { - return str; - } - final int pos = str.lastIndexOf(separator); - if (pos == INDEX_NOT_FOUND) { - return str; - } - return str.substring(0, pos); - } - - /** - *

- * Gets the String that is nested in between two instances of the same String. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} tag returns - * {@code null}. - *

- * - *
-	 * StringUtils.substringBetween(null, *)            = null
-	 * StringUtils.substringBetween("", "")             = ""
-	 * StringUtils.substringBetween("", "tag")          = null
-	 * StringUtils.substringBetween("tagabctag", null)  = null
-	 * StringUtils.substringBetween("tagabctag", "")    = ""
-	 * StringUtils.substringBetween("tagabctag", "tag") = "abc"
-	 * 
- * - * @param str the String containing the substring, may be null - * @param tag the String before and after the substring, may be null - * @return the substring, {@code null} if no match - * @since 2.0 - */ - public static String substringBetween(final String str, final String tag) { - return substringBetween(str, tag, tag); - } - - /** - *

- * Gets the String that is nested in between two Strings. Only the first match - * is returned. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} open/close - * returns {@code null} (no match). An empty ("") open and close returns an - * empty string. - *

- * - *
-	 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
-	 * StringUtils.substringBetween(null, *, *)          = null
-	 * StringUtils.substringBetween(*, null, *)          = null
-	 * StringUtils.substringBetween(*, *, null)          = null
-	 * StringUtils.substringBetween("", "", "")          = ""
-	 * StringUtils.substringBetween("", "", "]")         = null
-	 * StringUtils.substringBetween("", "[", "]")        = null
-	 * StringUtils.substringBetween("yabcz", "", "")     = ""
-	 * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
-	 * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
-	 * 
- * - * @param str the String containing the substring, may be null - * @param open the String before the substring, may be null - * @param close the String after the substring, may be null - * @return the substring, {@code null} if no match - * @since 2.0 - */ - public static String substringBetween(final String str, final String open, final String close) { - if (!ObjectUtils.allNotNull(str, open, close)) { - return null; - } - final int start = str.indexOf(open); - if (start != INDEX_NOT_FOUND) { - final int end = str.indexOf(close, start + open.length()); - if (end != INDEX_NOT_FOUND) { - return str.substring(start + open.length(), end); - } - } - return null; - } - - /** - *

- * Searches a String for substrings delimited by a start and end tag, returning - * all matching substrings in an array. - *

- * - *

- * A {@code null} input String returns {@code null}. A {@code null} open/close - * returns {@code null} (no match). An empty ("") open/close returns - * {@code null} (no match). - *

- * - *
-	 * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
-	 * StringUtils.substringsBetween(null, *, *)            = null
-	 * StringUtils.substringsBetween(*, null, *)            = null
-	 * StringUtils.substringsBetween(*, *, null)            = null
-	 * StringUtils.substringsBetween("", "[", "]")          = []
-	 * 
- * - * @param str the String containing the substrings, null returns null, empty - * returns empty - * @param open the String identifying the start of the substring, empty returns - * null - * @param close the String identifying the end of the substring, empty returns - * null - * @return a String Array of substrings, or {@code null} if no match - * @since 2.3 - */ - public static String[] substringsBetween(final String str, final String open, final String close) { - if (str == null || isEmpty(open) || isEmpty(close)) { - return null; - } - final int strLen = str.length(); - if (strLen == 0) { - return new String[0]; - } - final int closeLen = close.length(); - final int openLen = open.length(); - final List list = new ArrayList<>(); - int pos = 0; - while (pos < strLen - closeLen) { - int start = str.indexOf(open, pos); - if (start < 0) { - break; - } - start += openLen; - final int end = str.indexOf(close, start); - if (end < 0) { - break; - } - list.add(str.substring(start, end)); - pos = end + closeLen; - } - if (list.isEmpty()) { - return null; - } - return list.toArray(new String[0]); - } - - /** - *

- * Swaps the case of a String changing upper and title case to lower case, and - * lower case to upper case. - *

- * - *
    - *
  • Upper case character converts to Lower case
  • - *
  • Title case character converts to Lower case
  • - *
  • Lower case character converts to Upper case
  • - *
- * - *

- * For a word based algorithm, see - * {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}. A - * {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.swapCase(null)                 = null
-	 * StringUtils.swapCase("")                   = ""
-	 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
-	 * 
- * - *

- * NOTE: This method changed in Lang version 2.0. It no longer performs a word - * based algorithm. If you only use ASCII, you will notice no change. That - * functionality is available in org.apache.commons.lang3.text.WordUtils. - *

- * - * @param str the String to swap case, may be null - * @return the changed String, {@code null} if null String input - */ - public static String swapCase(final String str) { - if (isEmpty(str)) { - return str; - } - - final int strLen = str.length(); - final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array - int outOffset = 0; - for (int i = 0; i < strLen;) { - final int oldCodepoint = str.codePointAt(i); - final int newCodePoint; - if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) { - newCodePoint = Character.toLowerCase(oldCodepoint); - } else if (Character.isLowerCase(oldCodepoint)) { - newCodePoint = Character.toUpperCase(oldCodepoint); - } else { - newCodePoint = oldCodepoint; - } - newCodePoints[outOffset++] = newCodePoint; - i += Character.charCount(newCodePoint); - } - return new String(newCodePoints, 0, outOffset); - } - - /** - *

- * Converts a {@code CharSequence} into an array of code points. - *

- * - *

- * Valid pairs of surrogate code units will be converted into a single - * supplementary code point. Isolated surrogate code units (i.e. a high - * surrogate not followed by a low surrogate or a low surrogate not preceded by - * a high surrogate) will be returned as-is. - *

- * - *
-	 * StringUtils.toCodePoints(null)   =  null
-	 * StringUtils.toCodePoints("")     =  []  // empty array
-	 * 
- * - * @param cs the character sequence to convert - * @return an array of code points - * @since 3.6 - */ - public static int[] toCodePoints(final CharSequence cs) { - if (cs == null) { - return null; - } - if (cs.length() == 0) { - return new int[0]; - } - - final String s = cs.toString(); - final int[] result = new int[s.codePointCount(0, s.length())]; - int index = 0; - for (int i = 0; i < result.length; i++) { - result[i] = s.codePointAt(index); - index += Character.charCount(result[i]); - } - return result; - } - - /** - * Converts a {@code byte[]} to a String using the specified character encoding. - * - * @param bytes the byte array to read from - * @param charset the encoding to use, if null then use the platform default - * @return a new String - * @throws NullPointerException if {@code bytes} is null - * @since 3.2 - * @since 3.3 No longer throws {@link UnsupportedEncodingException}. - */ - public static String toEncodedString(final byte[] bytes, final Charset charset) { - return new String(bytes, Charsets.toCharset(charset)); - } - - /** - * Converts the given source String as a lower-case using the - * {@link Locale#ROOT} locale in a null-safe manner. - * - * @param source A source String or null. - * @return the given source String as a lower-case using the {@link Locale#ROOT} - * locale or null. - * @since 3.10 - */ - public static String toRootLowerCase(final String source) { - return source == null ? null : source.toLowerCase(Locale.ROOT); - } - - /** - * Converts the given source String as a upper-case using the - * {@link Locale#ROOT} locale in a null-safe manner. - * - * @param source A source String or null. - * @return the given source String as a upper-case using the {@link Locale#ROOT} - * locale or null. - * @since 3.10 - */ - public static String toRootUpperCase(final String source) { - return source == null ? null : source.toUpperCase(Locale.ROOT); - } - - /** - * Converts a {@code byte[]} to a String using the specified character encoding. - * - * @param bytes the byte array to read from - * @param charsetName the encoding to use, if null then use the platform default - * @return a new String - * @throws UnsupportedEncodingException If the named charset is not supported - * @throws NullPointerException if the input is null - * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead - * of String constants in your code - * @since 3.1 - */ - @Deprecated - public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException { - return new String(bytes, Charsets.toCharset(charsetName)); - } - - private static String toStringOrEmpty(final Object obj) { - return Objects.toString(obj, EMPTY); - } - - /** - *

- * Removes control characters (char <= 32) from both ends of this String, - * handling {@code null} by returning {@code null}. - *

- * - *

- * The String is trimmed using {@link String#trim()}. Trim removes start and end - * characters <= 32. To strip whitespace use {@link #strip(String)}. - *

- * - *

- * To trim your choice of characters, use the {@link #strip(String, String)} - * methods. - *

- * - *
-	 * StringUtils.trim(null)          = null
-	 * StringUtils.trim("")            = ""
-	 * StringUtils.trim("     ")       = ""
-	 * StringUtils.trim("abc")         = "abc"
-	 * StringUtils.trim("    abc    ") = "abc"
-	 * 
- * - * @param str the String to be trimmed, may be null - * @return the trimmed string, {@code null} if null String input - */ - public static String trim(final String str) { - return str == null ? null : str.trim(); - } - - /** - *

- * Removes control characters (char <= 32) from both ends of this String - * returning an empty String ("") if the String is empty ("") after the trim or - * if it is {@code null}. - * - *

- * The String is trimmed using {@link String#trim()}. Trim removes start and end - * characters <= 32. To strip whitespace use {@link #stripToEmpty(String)}. - *

- * - *
-	 * StringUtils.trimToEmpty(null)          = ""
-	 * StringUtils.trimToEmpty("")            = ""
-	 * StringUtils.trimToEmpty("     ")       = ""
-	 * StringUtils.trimToEmpty("abc")         = "abc"
-	 * StringUtils.trimToEmpty("    abc    ") = "abc"
-	 * 
- * - * @param str the String to be trimmed, may be null - * @return the trimmed String, or an empty String if {@code null} input - * @since 2.0 - */ - public static String trimToEmpty(final String str) { - return str == null ? EMPTY : str.trim(); - } - - /** - *

- * Removes control characters (char <= 32) from both ends of this String - * returning {@code null} if the String is empty ("") after the trim or if it is - * {@code null}. - * - *

- * The String is trimmed using {@link String#trim()}. Trim removes start and end - * characters <= 32. To strip whitespace use {@link #stripToNull(String)}. - *

- * - *
-	 * StringUtils.trimToNull(null)          = null
-	 * StringUtils.trimToNull("")            = null
-	 * StringUtils.trimToNull("     ")       = null
-	 * StringUtils.trimToNull("abc")         = "abc"
-	 * StringUtils.trimToNull("    abc    ") = "abc"
-	 * 
- * - * @param str the String to be trimmed, may be null - * @return the trimmed String, {@code null} if only chars <= 32, empty or - * null String input - * @since 2.0 - */ - public static String trimToNull(final String str) { - final String ts = trim(str); - return isEmpty(ts) ? null : ts; - } - - /** - *

- * Truncates a String. This will turn "Now is the time for all good men" into - * "Now is the time for". - *

- * - *

- * Specifically: - *

- *
    - *
  • If {@code str} is less than {@code maxWidth} characters long, return - * it.
  • - *
  • Else truncate it to {@code substring(str, 0, maxWidth)}.
  • - *
  • If {@code maxWidth} is less than {@code 0}, throw an - * {@code IllegalArgumentException}.
  • - *
  • In no case will it return a String of length greater than - * {@code maxWidth}.
  • - *
- * - *
-	 * StringUtils.truncate(null, 0)       = null
-	 * StringUtils.truncate(null, 2)       = null
-	 * StringUtils.truncate("", 4)         = ""
-	 * StringUtils.truncate("abcdefg", 4)  = "abcd"
-	 * StringUtils.truncate("abcdefg", 6)  = "abcdef"
-	 * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
-	 * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
-	 * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
-	 * 
- * - * @param str the String to truncate, may be null - * @param maxWidth maximum length of result String, must be positive - * @return truncated String, {@code null} if null String input - * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0} - * @since 3.5 - */ - public static String truncate(final String str, final int maxWidth) { - return truncate(str, 0, maxWidth); - } - - /** - *

- * Truncates a String. This will turn "Now is the time for all good men" into - * "is the time for all". - *

- * - *

- * Works like {@code truncate(String, int)}, but allows you to specify a "left - * edge" offset. - * - *

- * Specifically: - *

- *
    - *
  • If {@code str} is less than {@code maxWidth} characters long, return - * it.
  • - *
  • Else truncate it to {@code substring(str, offset, maxWidth)}.
  • - *
  • If {@code maxWidth} is less than {@code 0}, throw an - * {@code IllegalArgumentException}.
  • - *
  • If {@code offset} is less than {@code 0}, throw an - * {@code IllegalArgumentException}.
  • - *
  • In no case will it return a String of length greater than - * {@code maxWidth}.
  • - *
- * - *
-	 * StringUtils.truncate(null, 0, 0) = null
-	 * StringUtils.truncate(null, 2, 4) = null
-	 * StringUtils.truncate("", 0, 10) = ""
-	 * StringUtils.truncate("", 2, 10) = ""
-	 * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
-	 * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
-	 * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
-	 * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
-	 * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
-	 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
-	 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
-	 * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
-	 * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
-	 * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
-	 * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
-	 * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
-	 * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
-	 * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
-	 * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
-	 * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
-	 * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
-	 * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
-	 * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
-	 * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
-	 * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
-	 * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
-	 * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
-	 * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
-	 * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
-	 * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
-	 * 
- * - * @param str the String to truncate, may be null - * @param offset left edge of source String - * @param maxWidth maximum length of result String, must be positive - * @return truncated String, {@code null} if null String input - * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is - * less than {@code 0} - * @since 3.5 - */ - public static String truncate(final String str, final int offset, final int maxWidth) { - if (offset < 0) { - throw new IllegalArgumentException("offset cannot be negative"); - } - if (maxWidth < 0) { - throw new IllegalArgumentException("maxWith cannot be negative"); - } - if (str == null) { - return null; - } - if (offset > str.length()) { - return EMPTY; - } - if (str.length() > maxWidth) { - final int ix = Math.min(offset + maxWidth, str.length()); - return str.substring(offset, ix); - } - return str.substring(offset); - } - - /** - *

- * Uncapitalizes a String, changing the first character to lower case as per - * {@link Character#toLowerCase(int)}. No other characters are changed. - *

- * - *

- * For a word based algorithm, see - * {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}. A - * {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.uncapitalize(null)  = null
-	 * StringUtils.uncapitalize("")    = ""
-	 * StringUtils.uncapitalize("cat") = "cat"
-	 * StringUtils.uncapitalize("Cat") = "cat"
-	 * StringUtils.uncapitalize("CAT") = "cAT"
-	 * 
- * - * @param str the String to uncapitalize, may be null - * @return the uncapitalized String, {@code null} if null String input - * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String) - * @see #capitalize(String) - * @since 2.0 - */ - public static String uncapitalize(final String str) { - final int strLen = length(str); - if (strLen == 0) { - return str; - } - - final int firstCodepoint = str.codePointAt(0); - final int newCodePoint = Character.toLowerCase(firstCodepoint); - if (firstCodepoint == newCodePoint) { - // already capitalized - return str; - } - - final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array - int outOffset = 0; - newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint - for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen;) { - final int codepoint = str.codePointAt(inOffset); - newCodePoints[outOffset++] = codepoint; // copy the remaining ones - inOffset += Character.charCount(codepoint); - } - return new String(newCodePoints, 0, outOffset); - } - - /** - *

- * Unwraps a given string from a character. - *

- * - *
-	 * StringUtils.unwrap(null, null)         = null
-	 * StringUtils.unwrap(null, '\0')         = null
-	 * StringUtils.unwrap(null, '1')          = null
-	 * StringUtils.unwrap("a", 'a')           = "a"
-	 * StringUtils.unwrap("aa", 'a')           = ""
-	 * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
-	 * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
-	 * StringUtils.unwrap("A", '#')           = "A"
-	 * StringUtils.unwrap("#A", '#')          = "#A"
-	 * StringUtils.unwrap("A#", '#')          = "A#"
-	 * 
- * - * @param str the String to be unwrapped, can be null - * @param wrapChar the character used to unwrap - * @return unwrapped String or the original string if it is not quoted properly - * with the wrapChar - * @since 3.6 - */ - public static String unwrap(final String str, final char wrapChar) { - if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) { - return str; - } - - if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) { - final int startIndex = 0; - final int endIndex = str.length() - 1; - - return str.substring(startIndex + 1, endIndex); - } - - return str; - } - - /** - *

- * Unwraps a given string from anther string. - *

- * - *
-	 * StringUtils.unwrap(null, null)         = null
-	 * StringUtils.unwrap(null, "")           = null
-	 * StringUtils.unwrap(null, "1")          = null
-	 * StringUtils.unwrap("a", "a")           = "a"
-	 * StringUtils.unwrap("aa", "a")          = ""
-	 * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
-	 * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
-	 * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
-	 * StringUtils.unwrap("A", "#")           = "A"
-	 * StringUtils.unwrap("#A", "#")          = "#A"
-	 * StringUtils.unwrap("A#", "#")          = "A#"
-	 * 
- * - * @param str the String to be unwrapped, can be null - * @param wrapToken the String used to unwrap - * @return unwrapped String or the original string if it is not quoted properly - * with the wrapToken - * @since 3.6 - */ - public static String unwrap(final String str, final String wrapToken) { - if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) { - return str; - } - - if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) { - final int startIndex = str.indexOf(wrapToken); - final int endIndex = str.lastIndexOf(wrapToken); - final int wrapLength = wrapToken.length(); - - if (startIndex != -1 && endIndex != -1) { - return str.substring(startIndex + wrapLength, endIndex); - } - } - - return str; - } - - /** - *

- * Converts a String to upper case as per {@link String#toUpperCase()}. - *

- * - *

- * A {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.upperCase(null)  = null
-	 * StringUtils.upperCase("")    = ""
-	 * StringUtils.upperCase("aBc") = "ABC"
-	 * 
- * - *

- * Note: As described in the documentation for - * {@link String#toUpperCase()}, the result of this method is affected by the - * current locale. For platform-independent case transformations, the method - * {@link #lowerCase(String, Locale)} should be used with a specific locale - * (e.g. {@link Locale#ENGLISH}). - *

- * - * @param str the String to upper case, may be null - * @return the upper cased String, {@code null} if null String input - */ - public static String upperCase(final String str) { - if (str == null) { - return null; - } - return str.toUpperCase(); - } - - /** - *

- * Converts a String to upper case as per {@link String#toUpperCase(Locale)}. - *

- * - *

- * A {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.upperCase(null, Locale.ENGLISH)  = null
-	 * StringUtils.upperCase("", Locale.ENGLISH)    = ""
-	 * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
-	 * 
- * - * @param str the String to upper case, may be null - * @param locale the locale that defines the case transformation rules, must not - * be null - * @return the upper cased String, {@code null} if null String input - * @since 2.5 - */ - public static String upperCase(final String str, final Locale locale) { - if (str == null) { - return null; - } - return str.toUpperCase(LocaleUtils.toLocale(locale)); - } - - /** - * Returns the string representation of the {@code char} array or null. - * - * @param value the character array. - * @return a String or null - * @see String#valueOf(char[]) - * @since 3.9 - */ - public static String valueOf(final char[] value) { - return value == null ? null : String.valueOf(value); - } - - /** - *

- * Wraps a string with a char. - *

- * - *
-	 * StringUtils.wrap(null, *)        = null
-	 * StringUtils.wrap("", *)          = ""
-	 * StringUtils.wrap("ab", '\0')     = "ab"
-	 * StringUtils.wrap("ab", 'x')      = "xabx"
-	 * StringUtils.wrap("ab", '\'')     = "'ab'"
-	 * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
-	 * 
- * - * @param str the string to be wrapped, may be {@code null} - * @param wrapWith the char that will wrap {@code str} - * @return the wrapped string, or {@code null} if {@code str==null} - * @since 3.4 - */ - public static String wrap(final String str, final char wrapWith) { - - if (isEmpty(str) || wrapWith == CharUtils.NUL) { - return str; - } - - return wrapWith + str + wrapWith; - } - - /** - *

- * Wraps a String with another String. - *

- * - *

- * A {@code null} input String returns {@code null}. - *

- * - *
-	 * StringUtils.wrap(null, *)         = null
-	 * StringUtils.wrap("", *)           = ""
-	 * StringUtils.wrap("ab", null)      = "ab"
-	 * StringUtils.wrap("ab", "x")       = "xabx"
-	 * StringUtils.wrap("ab", "\"")      = "\"ab\""
-	 * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
-	 * StringUtils.wrap("ab", "'")       = "'ab'"
-	 * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
-	 * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
-	 * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
-	 * 
- * - * @param str the String to be wrapper, may be null - * @param wrapWith the String that will wrap str - * @return wrapped String, {@code null} if null String input - * @since 3.4 - */ - public static String wrap(final String str, final String wrapWith) { - - if (isEmpty(str) || isEmpty(wrapWith)) { - return str; - } - - return wrapWith.concat(str).concat(wrapWith); - } - - /** - *

- * Wraps a string with a char if that char is missing from the start or end of - * the given string. - *

- * - *

- * A new {@code String} will not be created if {@code str} is already wrapped. - *

- * - *
-	 * StringUtils.wrapIfMissing(null, *)        = null
-	 * StringUtils.wrapIfMissing("", *)          = ""
-	 * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
-	 * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
-	 * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
-	 * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
-	 * StringUtils.wrapIfMissing("/", '/')  = "/"
-	 * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
-	 * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
-	 * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
-	 * 
- * - * @param str the string to be wrapped, may be {@code null} - * @param wrapWith the char that will wrap {@code str} - * @return the wrapped string, or {@code null} if {@code str==null} - * @since 3.5 - */ - public static String wrapIfMissing(final String str, final char wrapWith) { - if (isEmpty(str) || wrapWith == CharUtils.NUL) { - return str; - } - final boolean wrapStart = str.charAt(0) != wrapWith; - final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith; - if (!wrapStart && !wrapEnd) { - return str; - } - - final StringBuilder builder = new StringBuilder(str.length() + 2); - if (wrapStart) { - builder.append(wrapWith); - } - builder.append(str); - if (wrapEnd) { - builder.append(wrapWith); - } - return builder.toString(); - } - - /** - *

- * Wraps a string with a string if that string is missing from the start or end - * of the given string. - *

- * - *

- * A new {@code String} will not be created if {@code str} is already wrapped. - *

- * - *
-	 * StringUtils.wrapIfMissing(null, *)         = null
-	 * StringUtils.wrapIfMissing("", *)           = ""
-	 * StringUtils.wrapIfMissing("ab", null)      = "ab"
-	 * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
-	 * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
-	 * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
-	 * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
-	 * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
-	 * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
-	 * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
-	 * StringUtils.wrapIfMissing("/", "/")  = "/"
-	 * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
-	 * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
-	 * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
-	 * 
- * - * @param str the string to be wrapped, may be {@code null} - * @param wrapWith the string that will wrap {@code str} - * @return the wrapped string, or {@code null} if {@code str==null} - * @since 3.5 - */ - public static String wrapIfMissing(final String str, final String wrapWith) { - if (isEmpty(str) || isEmpty(wrapWith)) { - return str; - } - - final boolean wrapStart = !str.startsWith(wrapWith); - final boolean wrapEnd = !str.endsWith(wrapWith); - if (!wrapStart && !wrapEnd) { - return str; - } - - final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length()); - if (wrapStart) { - builder.append(wrapWith); - } - builder.append(str); - if (wrapEnd) { - builder.append(wrapWith); - } - return builder.toString(); - } - - /** - *

- * {@code StringUtils} instances should NOT be constructed in standard - * programming. Instead, the class should be used as - * {@code StringUtils.trim(" foo ");}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public StringUtils() { - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/SystemUtils.java b/sources/main/java/org/apache/commons/lang3/SystemUtils.java deleted file mode 100644 index 4651c5fb..00000000 --- a/sources/main/java/org/apache/commons/lang3/SystemUtils.java +++ /dev/null @@ -1,1968 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -/** - *

- * Helpers for {@code java.lang.System}. - *

- *

- * If a system property cannot be read due to security restrictions, the - * corresponding field in this class will be set to {@code null} and a message - * will be written to {@code System.err}. - *

- *

- * #ThreadSafe# - *

- * - * @since 1.0 - */ -public class SystemUtils { - - /** - * The prefix String for all Windows OS. - */ - private static final String OS_NAME_WINDOWS_PREFIX = "Windows"; - - // System property constants - // ----------------------------------------------------------------------- - // These MUST be declared first. Other constants depend on this. - - /** - * The System property key for the user home directory. - */ - private static final String USER_HOME_KEY = "user.home"; - - /** - * The System property key for the user name. - */ - private static final String USER_NAME_KEY = "user.name"; - - /** - * The System property key for the user directory. - */ - private static final String USER_DIR_KEY = "user.dir"; - - /** - * The System property key for the Java IO temporary directory. - */ - private static final String JAVA_IO_TMPDIR_KEY = "java.io.tmpdir"; - - /** - * The System property key for the Java home directory. - */ - private static final String JAVA_HOME_KEY = "java.home"; - - /** - *

- * The {@code awt.toolkit} System Property. - *

- *

- * Holds a class name, on Windows XP this is {@code sun.awt.windows.WToolkit}. - *

- *

- * On platforms without a GUI, this value is {@code null}. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.1 - */ - public static final String AWT_TOOLKIT = getSystemProperty("awt.toolkit"); - - /** - *

- * The {@code file.encoding} System Property. - *

- *

- * File encoding, such as {@code Cp1252}. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.0 - * @since Java 1.2 - */ - public static final String FILE_ENCODING = getSystemProperty("file.encoding"); - - /** - *

- * The {@code file.separator} System Property. The file separator is: - *

- *
    - *
  • {@code "/"} on UNIX
  • - *
  • {@code "\"} on Windows.
  • - *
- * - *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @deprecated Use {@link File#separator}, since it is guaranteed to be a string - * containing a single character and it does not require a privilege - * check. - * @since Java 1.1 - */ - @Deprecated - public static final String FILE_SEPARATOR = getSystemProperty("file.separator"); - - /** - *

- * The {@code java.awt.fonts} System Property. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.1 - */ - public static final String JAVA_AWT_FONTS = getSystemProperty("java.awt.fonts"); - - /** - *

- * The {@code java.awt.graphicsenv} System Property. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.1 - */ - public static final String JAVA_AWT_GRAPHICSENV = getSystemProperty("java.awt.graphicsenv"); - - /** - *

- * The {@code java.awt.headless} System Property. The value of this property is - * the String {@code "true"} or {@code "false"}. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @see #isJavaAwtHeadless() - * @since 2.1 - * @since Java 1.4 - */ - public static final String JAVA_AWT_HEADLESS = getSystemProperty("java.awt.headless"); - - /** - *

- * The {@code java.awt.printerjob} System Property. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.1 - */ - public static final String JAVA_AWT_PRINTERJOB = getSystemProperty("java.awt.printerjob"); - - /** - *

- * The {@code java.class.path} System Property. Java class path. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String JAVA_CLASS_PATH = getSystemProperty("java.class.path"); - - /** - *

- * The {@code java.class.version} System Property. Java class format version - * number. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String JAVA_CLASS_VERSION = getSystemProperty("java.class.version"); - - /** - *

- * The {@code java.compiler} System Property. Name of JIT compiler to use. First - * in JDK version 1.2. Not used in Sun JDKs after 1.2. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2. Not used in Sun versions after 1.2. - */ - public static final String JAVA_COMPILER = getSystemProperty("java.compiler"); - - /** - *

- * The {@code java.endorsed.dirs} System Property. Path of endorsed directory or - * directories. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.4 - */ - public static final String JAVA_ENDORSED_DIRS = getSystemProperty("java.endorsed.dirs"); - - /** - *

- * The {@code java.ext.dirs} System Property. Path of extension directory or - * directories. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.3 - */ - public static final String JAVA_EXT_DIRS = getSystemProperty("java.ext.dirs"); - - /** - *

- * The {@code java.home} System Property. Java installation directory. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String JAVA_HOME = getSystemProperty(JAVA_HOME_KEY); - - /** - *

- * The {@code java.io.tmpdir} System Property. Default temp file path. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2 - */ - public static final String JAVA_IO_TMPDIR = getSystemProperty(JAVA_IO_TMPDIR_KEY); - - /** - *

- * The {@code java.library.path} System Property. List of paths to search when - * loading libraries. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2 - */ - public static final String JAVA_LIBRARY_PATH = getSystemProperty("java.library.path"); - - /** - *

- * The {@code java.runtime.name} System Property. Java Runtime Environment name. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.0 - * @since Java 1.3 - */ - public static final String JAVA_RUNTIME_NAME = getSystemProperty("java.runtime.name"); - - /** - *

- * The {@code java.runtime.version} System Property. Java Runtime Environment - * version. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.0 - * @since Java 1.3 - */ - public static final String JAVA_RUNTIME_VERSION = getSystemProperty("java.runtime.version"); - - /** - *

- * The {@code java.specification.name} System Property. Java Runtime Environment - * specification name. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2 - */ - public static final String JAVA_SPECIFICATION_NAME = getSystemProperty("java.specification.name"); - - /** - *

- * The {@code java.specification.vendor} System Property. Java Runtime - * Environment specification vendor. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2 - */ - public static final String JAVA_SPECIFICATION_VENDOR = getSystemProperty("java.specification.vendor"); - - /** - *

- * The {@code java.specification.version} System Property. Java Runtime - * Environment specification version. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.3 - */ - public static final String JAVA_SPECIFICATION_VERSION = getSystemProperty("java.specification.version"); - private static final JavaVersion JAVA_SPECIFICATION_VERSION_AS_ENUM = JavaVersion.get(JAVA_SPECIFICATION_VERSION); - - /** - *

- * The {@code java.util.prefs.PreferencesFactory} System Property. A class name. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.1 - * @since Java 1.4 - */ - public static final String JAVA_UTIL_PREFS_PREFERENCES_FACTORY = getSystemProperty( - "java.util.prefs.PreferencesFactory"); - - /** - *

- * The {@code java.vendor} System Property. Java vendor-specific string. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String JAVA_VENDOR = getSystemProperty("java.vendor"); - - /** - *

- * The {@code java.vendor.url} System Property. Java vendor URL. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String JAVA_VENDOR_URL = getSystemProperty("java.vendor.url"); - - /** - *

- * The {@code java.version} System Property. Java version number. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String JAVA_VERSION = getSystemProperty("java.version"); - - /** - *

- * The {@code java.vm.info} System Property. Java Virtual Machine implementation - * info. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.0 - * @since Java 1.2 - */ - public static final String JAVA_VM_INFO = getSystemProperty("java.vm.info"); - - /** - *

- * The {@code java.vm.name} System Property. Java Virtual Machine implementation - * name. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2 - */ - public static final String JAVA_VM_NAME = getSystemProperty("java.vm.name"); - - /** - *

- * The {@code java.vm.specification.name} System Property. Java Virtual Machine - * specification name. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2 - */ - public static final String JAVA_VM_SPECIFICATION_NAME = getSystemProperty("java.vm.specification.name"); - - /** - *

- * The {@code java.vm.specification.vendor} System Property. Java Virtual - * Machine specification vendor. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2 - */ - public static final String JAVA_VM_SPECIFICATION_VENDOR = getSystemProperty("java.vm.specification.vendor"); - - /** - *

- * The {@code java.vm.specification.version} System Property. Java Virtual - * Machine specification version. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2 - */ - public static final String JAVA_VM_SPECIFICATION_VERSION = getSystemProperty("java.vm.specification.version"); - - /** - *

- * The {@code java.vm.vendor} System Property. Java Virtual Machine - * implementation vendor. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2 - */ - public static final String JAVA_VM_VENDOR = getSystemProperty("java.vm.vendor"); - - /** - *

- * The {@code java.vm.version} System Property. Java Virtual Machine - * implementation version. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.2 - */ - public static final String JAVA_VM_VERSION = getSystemProperty("java.vm.version"); - - /** - *

- * The {@code line.separator} System Property. Line separator - * ({@code "\n"} on UNIX). - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @deprecated Use {@link System#lineSeparator()} instead, since it does not - * require a privilege check. - * @since Java 1.1 - */ - @Deprecated - public static final String LINE_SEPARATOR = getSystemProperty("line.separator"); - - /** - *

- * The {@code os.arch} System Property. Operating system architecture. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String OS_ARCH = getSystemProperty("os.arch"); - - /** - *

- * The {@code os.name} System Property. Operating system name. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String OS_NAME = getSystemProperty("os.name"); - - /** - *

- * The {@code os.version} System Property. Operating system version. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String OS_VERSION = getSystemProperty("os.version"); - - /** - *

- * The {@code path.separator} System Property. Path separator - * ({@code ":"} on UNIX). - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @deprecated Use {@link File#pathSeparator}, since it is guaranteed to be a - * string containing a single character and it does not require a - * privilege check. - * @since Java 1.1 - */ - @Deprecated - public static final String PATH_SEPARATOR = getSystemProperty("path.separator"); - - /** - *

- * The {@code user.country} or {@code user.region} System Property. User's - * country code, such as {@code GB}. First in Java version 1.2 as - * {@code user.region}. Renamed to {@code user.country} in 1.4 - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.0 - * @since Java 1.2 - */ - public static final String USER_COUNTRY = getSystemProperty("user.country") == null - ? getSystemProperty("user.region") - : getSystemProperty("user.country"); - - /** - *

- * The {@code user.dir} System Property. User's current working directory. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String USER_DIR = getSystemProperty(USER_DIR_KEY); - - /** - *

- * The {@code user.home} System Property. User's home directory. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String USER_HOME = getSystemProperty(USER_HOME_KEY); - - /** - *

- * The {@code user.language} System Property. User's language code, such as - * {@code "en"}. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.0 - * @since Java 1.2 - */ - public static final String USER_LANGUAGE = getSystemProperty("user.language"); - - /** - *

- * The {@code user.name} System Property. User's account name. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since Java 1.1 - */ - public static final String USER_NAME = getSystemProperty(USER_NAME_KEY); - - /** - *

- * The {@code user.timezone} System Property. For example: - * {@code "America/Los_Angeles"}. - *

- *

- * Defaults to {@code null} if the runtime does not have security access to read - * this property or the property does not exist. - *

- *

- * This value is initialized when the class is loaded. If - * {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class - * is loaded, the value will be out of sync with that System property. - *

- * - * @since 2.1 - */ - public static final String USER_TIMEZONE = getSystemProperty("user.timezone"); - - // Java version checks - // ----------------------------------------------------------------------- - // These MUST be declared after those above as they depend on the - // values being set up - - /** - *

- * Is {@code true} if this is Java version 1.1 (also 1.1.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- */ - public static final boolean IS_JAVA_1_1 = getJavaVersionMatches("1.1"); - - /** - *

- * Is {@code true} if this is Java version 1.2 (also 1.2.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- */ - public static final boolean IS_JAVA_1_2 = getJavaVersionMatches("1.2"); - - /** - *

- * Is {@code true} if this is Java version 1.3 (also 1.3.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- */ - public static final boolean IS_JAVA_1_3 = getJavaVersionMatches("1.3"); - - /** - *

- * Is {@code true} if this is Java version 1.4 (also 1.4.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- */ - public static final boolean IS_JAVA_1_4 = getJavaVersionMatches("1.4"); - - /** - *

- * Is {@code true} if this is Java version 1.5 (also 1.5.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- */ - public static final boolean IS_JAVA_1_5 = getJavaVersionMatches("1.5"); - - /** - *

- * Is {@code true} if this is Java version 1.6 (also 1.6.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- */ - public static final boolean IS_JAVA_1_6 = getJavaVersionMatches("1.6"); - - /** - *

- * Is {@code true} if this is Java version 1.7 (also 1.7.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- * - * @since 3.0 - */ - public static final boolean IS_JAVA_1_7 = getJavaVersionMatches("1.7"); - - /** - *

- * Is {@code true} if this is Java version 1.8 (also 1.8.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- * - * @since 3.3.2 - */ - public static final boolean IS_JAVA_1_8 = getJavaVersionMatches("1.8"); - - /** - *

- * Is {@code true} if this is Java version 1.9 (also 1.9.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- * - * @since 3.4 - * - * @deprecated As of release 3.5, replaced by {@link #IS_JAVA_9} - */ - @Deprecated - public static final boolean IS_JAVA_1_9 = getJavaVersionMatches("9"); - - /** - *

- * Is {@code true} if this is Java version 9 (also 9.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- * - * @since 3.5 - */ - public static final boolean IS_JAVA_9 = getJavaVersionMatches("9"); - - /** - *

- * Is {@code true} if this is Java version 10 (also 10.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- * - * @since 3.7 - */ - public static final boolean IS_JAVA_10 = getJavaVersionMatches("10"); - - /** - *

- * Is {@code true} if this is Java version 11 (also 11.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- * - * @since 3.8 - */ - public static final boolean IS_JAVA_11 = getJavaVersionMatches("11"); - - /** - *

- * Is {@code true} if this is Java version 12 (also 12.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- * - * @since 3.9 - */ - public static final boolean IS_JAVA_12 = getJavaVersionMatches("12"); - - /** - *

- * Is {@code true} if this is Java version 13 (also 13.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- * - * @since 3.9 - */ - public static final boolean IS_JAVA_13 = getJavaVersionMatches("13"); - - /** - *

- * Is {@code true} if this is Java version 14 (also 14.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- * - * @since 3.10 - */ - public static final boolean IS_JAVA_14 = getJavaVersionMatches("14"); - - /** - *

- * Is {@code true} if this is Java version 15 (also 15.x versions). - *

- *

- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *

- * - * @since 3.10 - */ - public static final boolean IS_JAVA_15 = getJavaVersionMatches("15"); - - // Operating system checks - // ----------------------------------------------------------------------- - // These MUST be declared after those above as they depend on the - // values being set up - // OS names from http://www.vamphq.com/os.html - // Selected ones included - please advise dev@commons.apache.org - // if you want another added or a mistake corrected - - /** - *

- * Is {@code true} if this is AIX. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_AIX = getOsMatchesName("AIX"); - - /** - *

- * Is {@code true} if this is HP-UX. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_HP_UX = getOsMatchesName("HP-UX"); - - /** - *

- * Is {@code true} if this is IBM OS/400. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.3 - */ - public static final boolean IS_OS_400 = getOsMatchesName("OS/400"); - - /** - *

- * Is {@code true} if this is Irix. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_IRIX = getOsMatchesName("Irix"); - - /** - *

- * Is {@code true} if this is Linux. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_LINUX = getOsMatchesName("Linux") || getOsMatchesName("LINUX"); - - /** - *

- * Is {@code true} if this is Mac. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_MAC = getOsMatchesName("Mac"); - - /** - *

- * Is {@code true} if this is Mac. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_MAC_OSX = getOsMatchesName("Mac OS X"); - - /** - *

- * Is {@code true} if this is Mac OS X Cheetah. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_CHEETAH = getOsMatches("Mac OS X", "10.0"); - - /** - *

- * Is {@code true} if this is Mac OS X Puma. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_PUMA = getOsMatches("Mac OS X", "10.1"); - - /** - *

- * Is {@code true} if this is Mac OS X Jaguar. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_JAGUAR = getOsMatches("Mac OS X", "10.2"); - - /** - *

- * Is {@code true} if this is Mac OS X Panther. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_PANTHER = getOsMatches("Mac OS X", "10.3"); - - /** - *

- * Is {@code true} if this is Mac OS X Tiger. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_TIGER = getOsMatches("Mac OS X", "10.4"); - - /** - *

- * Is {@code true} if this is Mac OS X Leopard. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_LEOPARD = getOsMatches("Mac OS X", "10.5"); - - /** - *

- * Is {@code true} if this is Mac OS X Snow Leopard. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_SNOW_LEOPARD = getOsMatches("Mac OS X", "10.6"); - - /** - *

- * Is {@code true} if this is Mac OS X Lion. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_LION = getOsMatches("Mac OS X", "10.7"); - - /** - *

- * Is {@code true} if this is Mac OS X Mountain Lion. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_MOUNTAIN_LION = getOsMatches("Mac OS X", "10.8"); - - /** - *

- * Is {@code true} if this is Mac OS X Mavericks. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_MAVERICKS = getOsMatches("Mac OS X", "10.9"); - - /** - *

- * Is {@code true} if this is Mac OS X Yosemite. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_MAC_OSX_YOSEMITE = getOsMatches("Mac OS X", "10.10"); - - /** - *

- * Is {@code true} if this is Mac OS X El Capitan. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.5 - */ - public static final boolean IS_OS_MAC_OSX_EL_CAPITAN = getOsMatches("Mac OS X", "10.11"); - - /** - *

- * Is {@code true} if this is Mac OS X Sierra. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.12.0 - */ - public static final boolean IS_OS_MAC_OSX_SIERRA = getOsMatches("Mac OS X", "10.12"); - - /** - *

- * Is {@code true} if this is Mac OS X High Sierra. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.12.0 - */ - public static final boolean IS_OS_MAC_OSX_HIGH_SIERRA = getOsMatches("Mac OS X", "10.13"); - - /** - *

- * Is {@code true} if this is Mac OS X Mojave. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.12.0 - */ - public static final boolean IS_OS_MAC_OSX_MOJAVE = getOsMatches("Mac OS X", "10.14"); - - /** - *

- * Is {@code true} if this is Mac OS X Catalina. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.12.0 - */ - public static final boolean IS_OS_MAC_OSX_CATALINA = getOsMatches("Mac OS X", "10.15"); - - /** - *

- * Is {@code true} if this is Mac OS X Big Sur. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.12.0 - */ - public static final boolean IS_OS_MAC_OSX_BIG_SUR = getOsMatches("Mac OS X", "10.16"); - - /** - *

- * Is {@code true} if this is FreeBSD. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.1 - */ - public static final boolean IS_OS_FREE_BSD = getOsMatchesName("FreeBSD"); - - /** - *

- * Is {@code true} if this is OpenBSD. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.1 - */ - public static final boolean IS_OS_OPEN_BSD = getOsMatchesName("OpenBSD"); - - /** - *

- * Is {@code true} if this is NetBSD. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.1 - */ - public static final boolean IS_OS_NET_BSD = getOsMatchesName("NetBSD"); - - /** - *

- * Is {@code true} if this is OS/2. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_OS2 = getOsMatchesName("OS/2"); - - /** - *

- * Is {@code true} if this is Solaris. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_SOLARIS = getOsMatchesName("Solaris"); - - /** - *

- * Is {@code true} if this is SunOS. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_SUN_OS = getOsMatchesName("SunOS"); - - /** - *

- * Is {@code true} if this is a UNIX like system, as in any of AIX, HP-UX, Irix, - * Linux, MacOSX, Solaris or SUN OS. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.1 - */ - public static final boolean IS_OS_UNIX = IS_OS_AIX || IS_OS_HP_UX || IS_OS_IRIX || IS_OS_LINUX || IS_OS_MAC_OSX - || IS_OS_SOLARIS || IS_OS_SUN_OS || IS_OS_FREE_BSD || IS_OS_OPEN_BSD || IS_OS_NET_BSD; - - /** - *

- * Is {@code true} if this is Windows. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS = getOsMatchesName(OS_NAME_WINDOWS_PREFIX); - - /** - *

- * Is {@code true} if this is Windows 2000. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_2000 = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " 2000"); - - /** - *

- * Is {@code true} if this is Windows 2003. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.1 - */ - public static final boolean IS_OS_WINDOWS_2003 = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " 2003"); - - /** - *

- * Is {@code true} if this is Windows Server 2008. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.1 - */ - public static final boolean IS_OS_WINDOWS_2008 = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " Server 2008"); - - /** - *

- * Is {@code true} if this is Windows Server 2012. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.4 - */ - public static final boolean IS_OS_WINDOWS_2012 = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " Server 2012"); - - /** - *

- * Is {@code true} if this is Windows 95. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_95 = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " 95"); - - /** - *

- * Is {@code true} if this is Windows 98. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_98 = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " 98"); - - /** - *

- * Is {@code true} if this is Windows ME. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_ME = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " Me"); - - /** - *

- * Is {@code true} if this is Windows NT. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_NT = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " NT"); - - /** - *

- * Is {@code true} if this is Windows XP. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_XP = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " XP"); - - // ----------------------------------------------------------------------- - /** - *

- * Is {@code true} if this is Windows Vista. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 2.4 - */ - public static final boolean IS_OS_WINDOWS_VISTA = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " Vista"); - - /** - *

- * Is {@code true} if this is Windows 7. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.0 - */ - public static final boolean IS_OS_WINDOWS_7 = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " 7"); - - /** - *

- * Is {@code true} if this is Windows 8. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.2 - */ - public static final boolean IS_OS_WINDOWS_8 = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " 8"); - - /** - *

- * Is {@code true} if this is Windows 10. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.5 - */ - public static final boolean IS_OS_WINDOWS_10 = getOsMatchesName(OS_NAME_WINDOWS_PREFIX + " 10"); - - /** - *

- * Is {@code true} if this is z/OS. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- * - * @since 3.5 - */ - // Values on a z/OS system I tested (Gary Gregory - 2016-03-12) - // os.arch = s390x - // os.encoding = ISO8859_1 - // os.name = z/OS - // os.version = 02.02.00 - public static final boolean IS_OS_ZOS = getOsMatchesName("z/OS"); - - /** - *

- * Gets an environment variable, defaulting to {@code defaultValue} if the - * variable cannot be read. - *

- *

- * If a {@code SecurityException} is caught, the return value is - * {@code defaultValue} and a message is written to {@code System.err}. - *

- * - * @param name the environment variable name - * @param defaultValue the default value - * @return the environment variable value or {@code defaultValue} if a security - * problem occurs - * @since 3.8 - */ - public static String getEnvironmentVariable(final String name, final String defaultValue) { - try { - final String value = System.getenv(name); - return value == null ? defaultValue : value; - } catch (final SecurityException ex) { - // we are not allowed to look at this property - // System.err.println("Caught a SecurityException reading the environment - // variable '" + name + "'."); - return defaultValue; - } - } - - /** - * Gets the host name from an environment variable (COMPUTERNAME on Windows, - * HOSTNAME elsewhere). - * - *

- * If you want to know what the network stack says is the host name, you should - * use {@code InetAddress.getLocalHost().getHostName()}. - *

- * - * @return the host name. Will be {@code null} if the environment variable is - * not defined. - * @since 3.6 - */ - public static String getHostName() { - return IS_OS_WINDOWS ? System.getenv("COMPUTERNAME") : System.getenv("HOSTNAME"); - } - - /** - *

- * Decides if the Java version matches. - *

- * - * @param versionPrefix the prefix for the java version - * @return true if matches, or false if not or can't determine - */ - private static boolean getJavaVersionMatches(final String versionPrefix) { - return isJavaVersionMatch(JAVA_SPECIFICATION_VERSION, versionPrefix); - } - - /** - * Decides if the operating system matches. - * - * @param osNamePrefix the prefix for the OS name - * @param osVersionPrefix the prefix for the version - * @return true if matches, or false if not or can't determine - */ - private static boolean getOsMatches(final String osNamePrefix, final String osVersionPrefix) { - return isOSMatch(OS_NAME, OS_VERSION, osNamePrefix, osVersionPrefix); - } - - /** - * Decides if the operating system matches. - * - * @param osNamePrefix the prefix for the OS name - * @return true if matches, or false if not or can't determine - */ - private static boolean getOsMatchesName(final String osNamePrefix) { - return isOSNameMatch(OS_NAME, osNamePrefix); - } - - // ----------------------------------------------------------------------- - /** - *

- * Gets a System property, defaulting to {@code null} if the property cannot be - * read. - *

- *

- * If a {@code SecurityException} is caught, the return value is {@code null} - * and a message is written to {@code System.err}. - *

- * - * @param property the system property name - * @return the system property value or {@code null} if a security problem - * occurs - */ - private static String getSystemProperty(final String property) { - try { - return System.getProperty(property); - } catch (final SecurityException ex) { - // we are not allowed to look at this property - // System.err.println("Caught a SecurityException reading the system property '" - // + property - // + "'; the SystemUtils property value will default to null."); - return null; - } - } - - /** - *

- * Gets the user name. - *

- * - * @return a name - * @throws SecurityException if a security manager exists and its - * {@code checkPropertyAccess} method doesn't allow - * access to the specified system property. - * @see System#getProperty(String) - * @since 3.10 - */ - public static String getUserName() { - return System.getProperty(USER_NAME_KEY); - } - - /** - *

- * Gets the user name. - *

- * - * @param defaultValue A default value. - * @return a name - * @throws SecurityException if a security manager exists and its - * {@code checkPropertyAccess} method doesn't allow - * access to the specified system property. - * @see System#getProperty(String) - * @since 3.10 - */ - public static String getUserName(final String defaultValue) { - return System.getProperty(USER_NAME_KEY, defaultValue); - } - - /** - * Returns whether the {@link #JAVA_AWT_HEADLESS} value is {@code true}. - * - * @return {@code true} if {@code JAVA_AWT_HEADLESS} is {@code "true"}, - * {@code false} otherwise. - * @see #JAVA_AWT_HEADLESS - * @since 2.1 - * @since Java 1.4 - */ - public static boolean isJavaAwtHeadless() { - return Boolean.TRUE.toString().equals(JAVA_AWT_HEADLESS); - } - - /** - *

- * Is the Java version at least the requested version. - *

- *

- * - * @param requiredVersion the required version, for example 1.31f - * @return {@code true} if the actual version is equal or greater than the - * required version - */ - public static boolean isJavaVersionAtLeast(final JavaVersion requiredVersion) { - return JAVA_SPECIFICATION_VERSION_AS_ENUM.atLeast(requiredVersion); - } - - /** - *

- * Is the Java version at most the requested version. - *

- *

- * Example input: - *

- * - * @param requiredVersion the required version, for example 1.31f - * @return {@code true} if the actual version is equal or less than the required - * version - * @since 3.9 - */ - public static boolean isJavaVersionAtMost(final JavaVersion requiredVersion) { - return JAVA_SPECIFICATION_VERSION_AS_ENUM.atMost(requiredVersion); - } - - /** - *

- * Decides if the Java version matches. - *

- *

- * This method is package private instead of private to support unit test - * invocation. - *

- * - * @param version the actual Java version - * @param versionPrefix the prefix for the expected Java version - * @return true if matches, or false if not or can't determine - */ - static boolean isJavaVersionMatch(final String version, final String versionPrefix) { - if (version == null) { - return false; - } - return version.startsWith(versionPrefix); - } - - /** - * Decides if the operating system matches. - *

- * This method is package private instead of private to support unit test - * invocation. - *

- * - * @param osName the actual OS name - * @param osVersion the actual OS version - * @param osNamePrefix the prefix for the expected OS name - * @param osVersionPrefix the prefix for the expected OS version - * @return true if matches, or false if not or can't determine - */ - static boolean isOSMatch(final String osName, final String osVersion, final String osNamePrefix, - final String osVersionPrefix) { - if (osName == null || osVersion == null) { - return false; - } - return isOSNameMatch(osName, osNamePrefix) && isOSVersionMatch(osVersion, osVersionPrefix); - } - - /** - * Decides if the operating system matches. - *

- * This method is package private instead of private to support unit test - * invocation. - *

- * - * @param osName the actual OS name - * @param osNamePrefix the prefix for the expected OS name - * @return true if matches, or false if not or can't determine - */ - static boolean isOSNameMatch(final String osName, final String osNamePrefix) { - if (osName == null) { - return false; - } - return osName.startsWith(osNamePrefix); - } - - /** - * Decides if the operating system version matches. - *

- * This method is package private instead of private to support unit test - * invocation. - *

- * - * @param osVersion the actual OS version - * @param osVersionPrefix the prefix for the expected OS version - * @return true if matches, or false if not or can't determine - */ - static boolean isOSVersionMatch(final String osVersion, final String osVersionPrefix) { - if (StringUtils.isEmpty(osVersion)) { - return false; - } - // Compare parts of the version string instead of using - // String.startsWith(String) because otherwise - // osVersionPrefix 10.1 would also match osVersion 10.10 - final String[] versionPrefixParts = osVersionPrefix.split("\\."); - final String[] versionParts = osVersion.split("\\."); - for (int i = 0; i < Math.min(versionPrefixParts.length, versionParts.length); i++) { - if (!versionPrefixParts[i].equals(versionParts[i])) { - return false; - } - } - return true; - } - - // ----------------------------------------------------------------------- - /** - *

- * SystemUtils instances should NOT be constructed in standard programming. - * Instead, the class should be used as {@code SystemUtils.FILE_SEPARATOR}. - *

- *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public SystemUtils() { - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/ThreadUtils.java b/sources/main/java/org/apache/commons/lang3/ThreadUtils.java deleted file mode 100644 index a0281007..00000000 --- a/sources/main/java/org/apache/commons/lang3/ThreadUtils.java +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.lang3.time.DurationUtils; - -/** - *

- * Helpers for {@code java.lang.Thread} and {@code java.lang.ThreadGroup}. - *

- *

- * #ThreadSafe# - *

- * - * @see java.lang.Thread - * @see java.lang.ThreadGroup - * @since 3.5 - */ -public class ThreadUtils { - - /** - * A predicate implementation which always returns true. - */ - private static final class AlwaysTruePredicate implements ThreadPredicate, ThreadGroupPredicate { - - private AlwaysTruePredicate() { - } - - @Override - public boolean test(final Thread thread) { - return true; - } - - @Override - public boolean test(final ThreadGroup threadGroup) { - return true; - } - } - - /** - * A predicate implementation which matches a thread or threadgroup name. - */ - public static class NamePredicate implements ThreadPredicate, ThreadGroupPredicate { - - private final String name; - - /** - * Predicate constructor - * - * @param name thread or threadgroup name - * @throws IllegalArgumentException if the name is {@code null} - */ - public NamePredicate(final String name) { - Validate.notNull(name, "name"); - this.name = name; - } - - @Override - public boolean test(final Thread thread) { - return thread != null && thread.getName().equals(name); - } - - @Override - public boolean test(final ThreadGroup threadGroup) { - return threadGroup != null && threadGroup.getName().equals(name); - } - } - - /** - * A predicate for selecting threadgroups. - */ - // When breaking BC, replace this with Predicate - @FunctionalInterface - public interface ThreadGroupPredicate { - - /** - * Evaluates this predicate on the given threadgroup. - * - * @param threadGroup the threadgroup - * @return {@code true} if the threadGroup matches the predicate, otherwise - * {@code false} - */ - boolean test(ThreadGroup threadGroup); - } - - /** - * A predicate implementation which matches a thread id. - */ - public static class ThreadIdPredicate implements ThreadPredicate { - - private final long threadId; - - /** - * Predicate constructor - * - * @param threadId the threadId to match - * @throws IllegalArgumentException if the threadId is zero or negative - */ - public ThreadIdPredicate(final long threadId) { - if (threadId <= 0) { - throw new IllegalArgumentException("The thread id must be greater than zero"); - } - this.threadId = threadId; - } - - @Override - public boolean test(final Thread thread) { - return thread != null && thread.getId() == threadId; - } - } - - /** - * A predicate for selecting threads. - */ - // When breaking BC, replace this with Predicate - @FunctionalInterface - public interface ThreadPredicate { - - /** - * Evaluates this predicate on the given thread. - * - * @param thread the thread - * @return {@code true} if the thread matches the predicate, otherwise - * {@code false} - */ - boolean test(Thread thread); - } - - /** - * Predicate which always returns true. - */ - public static final AlwaysTruePredicate ALWAYS_TRUE_PREDICATE = new AlwaysTruePredicate(); - - /** - * Finds the active thread with the specified id. - * - * @param threadId The thread id - * @return The thread with the specified id or {@code null} if no such thread - * exists - * @throws IllegalArgumentException if the specified id is zero or negative - * @throws SecurityException if the current thread cannot access the - * system thread group - * - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Thread findThreadById(final long threadId) { - final Collection result = findThreads(new ThreadIdPredicate(threadId)); - return result.isEmpty() ? null : result.iterator().next(); - } - - /** - * Finds the active thread with the specified id if it belongs to a thread group - * with the specified group name. - * - * @param threadId The thread id - * @param threadGroupName The thread group name - * @return The threads which belongs to a thread group with the specified group - * name and the thread's id match the specified id. {@code null} is - * returned if no such thread exists - * @throws IllegalArgumentException if the specified id is zero or negative or - * the group name is null - * @throws SecurityException if the current thread cannot access the - * system thread group - * - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Thread findThreadById(final long threadId, final String threadGroupName) { - Validate.notNull(threadGroupName, "threadGroupName"); - final Thread thread = findThreadById(threadId); - if (thread != null && thread.getThreadGroup() != null - && thread.getThreadGroup().getName().equals(threadGroupName)) { - return thread; - } - return null; - } - - /** - * Finds the active thread with the specified id if it belongs to the specified - * thread group. - * - * @param threadId The thread id - * @param threadGroup The thread group - * @return The thread which belongs to a specified thread group and the thread's - * id match the specified id. {@code null} is returned if no such thread - * exists - * @throws IllegalArgumentException if the specified id is zero or negative or - * the group is null - * @throws SecurityException if the current thread cannot access the - * system thread group - * - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Thread findThreadById(final long threadId, final ThreadGroup threadGroup) { - Validate.notNull(threadGroup, "threadGroup"); - final Thread thread = findThreadById(threadId); - if (thread != null && threadGroup.equals(thread.getThreadGroup())) { - return thread; - } - return null; - } - - /** - * Select all active threadgroups which match the given predicate and which is a - * subgroup of the given thread group (or one of its subgroups). - * - * @param group the thread group - * @param recurse if {@code true} then evaluate the predicate recursively on - * all threadgroups in all subgroups of the given group - * @param predicate the predicate - * @return An unmodifiable {@code Collection} of active threadgroups which match - * the given predicate and which is a subgroup of the given thread group - * @throws IllegalArgumentException if the given group or predicate is null - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Collection findThreadGroups(final ThreadGroup group, final boolean recurse, - final ThreadGroupPredicate predicate) { - Validate.notNull(group, "group"); - Validate.notNull(predicate, "predicate"); - - int count = group.activeGroupCount(); - ThreadGroup[] threadGroups; - do { - threadGroups = new ThreadGroup[count + (count / 2) + 1]; // slightly grow the array size - count = group.enumerate(threadGroups, recurse); - // return value of enumerate() must be strictly less than the array size - // according to javadoc - } while (count >= threadGroups.length); - - final List result = new ArrayList<>(count); - for (int i = 0; i < count; ++i) { - if (predicate.test(threadGroups[i])) { - result.add(threadGroups[i]); - } - } - return Collections.unmodifiableCollection(result); - } - - /** - * Select all active threadgroups which match the given predicate. - * - * @param predicate the predicate - * @return An unmodifiable {@code Collection} of active threadgroups matching - * the given predicate - * @throws IllegalArgumentException if the predicate is null - * @throws SecurityException if the current thread cannot access the - * system thread group - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Collection findThreadGroups(final ThreadGroupPredicate predicate) { - return findThreadGroups(getSystemThreadGroup(), true, predicate); - } - - /** - * Finds active thread groups with the specified group name. - * - * @param threadGroupName The thread group name - * @return the thread groups with the specified group name or an empty - * collection if no such thread group exists. The collection returned is - * always unmodifiable. - * @throws IllegalArgumentException if group name is null - * @throws SecurityException if the current thread cannot access the - * system thread group - * - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Collection findThreadGroupsByName(final String threadGroupName) { - return findThreadGroups(new NamePredicate(threadGroupName)); - } - - /** - * Select all active threads which match the given predicate and which belongs - * to the given thread group (or one of its subgroups). - * - * @param group the thread group - * @param recurse if {@code true} then evaluate the predicate recursively on - * all threads in all subgroups of the given group - * @param predicate the predicate - * @return An unmodifiable {@code Collection} of active threads which match the - * given predicate and which belongs to the given thread group - * @throws IllegalArgumentException if the given group or predicate is null - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Collection findThreads(final ThreadGroup group, final boolean recurse, - final ThreadPredicate predicate) { - Validate.notNull(group, "The group must not be null"); - Validate.notNull(predicate, "The predicate must not be null"); - - int count = group.activeCount(); - Thread[] threads; - do { - threads = new Thread[count + (count / 2) + 1]; // slightly grow the array size - count = group.enumerate(threads, recurse); - // return value of enumerate() must be strictly less than the array size - // according to javadoc - } while (count >= threads.length); - - final List result = new ArrayList<>(count); - for (int i = 0; i < count; ++i) { - if (predicate.test(threads[i])) { - result.add(threads[i]); - } - } - return Collections.unmodifiableCollection(result); - } - - /** - * Select all active threads which match the given predicate. - * - * @param predicate the predicate - * @return An unmodifiable {@code Collection} of active threads matching the - * given predicate - * - * @throws IllegalArgumentException if the predicate is null - * @throws SecurityException if the current thread cannot access the - * system thread group - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Collection findThreads(final ThreadPredicate predicate) { - return findThreads(getSystemThreadGroup(), true, predicate); - } - - /** - * Finds active threads with the specified name. - * - * @param threadName The thread name - * @return The threads with the specified name or an empty collection if no such - * thread exists. The collection returned is always unmodifiable. - * @throws IllegalArgumentException if the specified name is null - * @throws SecurityException if the current thread cannot access the - * system thread group - * - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Collection findThreadsByName(final String threadName) { - return findThreads(new NamePredicate(threadName)); - } - - /** - * Finds active threads with the specified name if they belong to a thread group - * with the specified group name. - * - * @param threadName The thread name - * @param threadGroupName The thread group name - * @return The threads which belongs to a thread group with the specified group - * name and the thread's name match the specified name, An empty - * collection is returned if no such thread exists. The collection - * returned is always unmodifiable. - * @throws IllegalArgumentException if the specified thread name or group name - * is null - * @throws SecurityException if the current thread cannot access the - * system thread group - * - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Collection findThreadsByName(final String threadName, final String threadGroupName) { - Validate.notNull(threadName, "threadName"); - Validate.notNull(threadGroupName, "threadGroupName"); - - final Collection threadGroups = findThreadGroups(new NamePredicate(threadGroupName)); - - if (threadGroups.isEmpty()) { - return Collections.emptyList(); - } - - final Collection result = new ArrayList<>(); - final NamePredicate threadNamePredicate = new NamePredicate(threadName); - for (final ThreadGroup group : threadGroups) { - result.addAll(findThreads(group, false, threadNamePredicate)); - } - return Collections.unmodifiableCollection(result); - } - - /** - * Finds active threads with the specified name if they belong to a specified - * thread group. - * - * @param threadName The thread name - * @param threadGroup The thread group - * @return The threads which belongs to a thread group and the thread's name - * match the specified name, An empty collection is returned if no such - * thread exists. The collection returned is always unmodifiable. - * @throws IllegalArgumentException if the specified thread name or group is - * null - * @throws SecurityException if the current thread cannot access the - * system thread group - * - * @throws SecurityException if the current thread cannot modify thread - * groups from this thread's thread group up to - * the system thread group - */ - public static Collection findThreadsByName(final String threadName, final ThreadGroup threadGroup) { - return findThreads(threadGroup, false, new NamePredicate(threadName)); - } - - /** - * Gets all active thread groups excluding the system thread group (A thread - * group is active if it has been not destroyed). - * - * @return all thread groups excluding the system thread group. The collection - * returned is always unmodifiable. - * @throws SecurityException if the current thread cannot access the system - * thread group - * - * @throws SecurityException if the current thread cannot modify thread groups - * from this thread's thread group up to the system - * thread group - */ - public static Collection getAllThreadGroups() { - return findThreadGroups(ALWAYS_TRUE_PREDICATE); - } - - /** - * Gets all active threads (A thread is active if it has been started and has - * not yet died). - * - * @return all active threads. The collection returned is always unmodifiable. - * @throws SecurityException if the current thread cannot access the system - * thread group - * - * @throws SecurityException if the current thread cannot modify thread groups - * from this thread's thread group up to the system - * thread group - */ - public static Collection getAllThreads() { - return findThreads(ALWAYS_TRUE_PREDICATE); - } - - /** - * Gets the system thread group (sometimes also referred as "root thread - * group"). - * - * @return the system thread group - * @throws SecurityException if the current thread cannot modify thread groups - * from this thread's thread group up to the system - * thread group - */ - public static ThreadGroup getSystemThreadGroup() { - ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); - while (threadGroup.getParent() != null) { - threadGroup = threadGroup.getParent(); - } - return threadGroup; - } - - /** - * Waits for the given thread to die for the given duration. Implemented using - * {@link Thread#join(long, int)}. - * - * @param thread The thread to join. - * @param duration How long to wait. - * @throws InterruptedException if any thread has interrupted the current - * thread. - * @see Thread#join(long, int) - * @since 3.12.0 - */ - public static void join(final Thread thread, final Duration duration) throws InterruptedException { - DurationUtils.accept(thread::join, duration); - } - - /** - * Sleeps the current thread for the given duration. Implemented using - * {@link Thread#sleep(long, int)}. - * - * @param duration How long to sleep. - * @throws InterruptedException if any thread has interrupted the current - * thread. - * @see Thread#sleep(long, int) - * @since 3.12.0 - */ - public static void sleep(final Duration duration) throws InterruptedException { - DurationUtils.accept(Thread::sleep, duration); - } - - /** - *

- * ThreadUtils instances should NOT be constructed in standard programming. - * Instead, the class should be used as {@code ThreadUtils.getAllThreads()} - *

- *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public ThreadUtils() { - } -} diff --git a/sources/main/java/org/apache/commons/lang3/Validate.java b/sources/main/java/org/apache/commons/lang3/Validate.java deleted file mode 100644 index 136f9d6a..00000000 --- a/sources/main/java/org/apache/commons/lang3/Validate.java +++ /dev/null @@ -1,1620 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.regex.Pattern; - -import net.lax1dude.eaglercraft.v1_8.HString; -import net.lax1dude.eaglercraft.v1_8.JDKBackports; - -/** - *

- * This class assists in validating arguments. The validation methods are based - * along the following principles: - *

    - *
  • An invalid {@code null} argument causes a - * {@link NullPointerException}.
  • - *
  • A non-{@code null} argument causes an - * {@link IllegalArgumentException}.
  • - *
  • An invalid index into an array/collection/map/string causes an - * {@link IndexOutOfBoundsException}.
  • - *
- * - *

- * All exceptions messages are format - * strings as defined by the Java platform. For example: - *

- * - *
- * Validate.isTrue(i > 0, "The value must be greater than zero: %d", i);
- * Validate.notNull(surname, "The surname must not be %s", null);
- * 
- * - *

- * #ThreadSafe# - *

- * - * @see java.lang.String#format(String, Object...) - * @since 2.0 - */ -public class Validate { - - private static final String DEFAULT_NOT_NAN_EX_MESSAGE = "The validated value is not a number"; - private static final String DEFAULT_FINITE_EX_MESSAGE = "The value is invalid: %f"; - private static final String DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE = "The value %s is not in the specified exclusive range of %s to %s"; - private static final String DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE = "The value %s is not in the specified inclusive range of %s to %s"; - private static final String DEFAULT_MATCHES_PATTERN_EX = "The string %s does not match the pattern %s"; - private static final String DEFAULT_IS_NULL_EX_MESSAGE = "The validated object is null"; - private static final String DEFAULT_IS_TRUE_EX_MESSAGE = "The validated expression is false"; - private static final String DEFAULT_NO_NULL_ELEMENTS_ARRAY_EX_MESSAGE = "The validated array contains null element at index: %d"; - private static final String DEFAULT_NO_NULL_ELEMENTS_COLLECTION_EX_MESSAGE = "The validated collection contains null element at index: %d"; - private static final String DEFAULT_NOT_BLANK_EX_MESSAGE = "The validated character sequence is blank"; - private static final String DEFAULT_NOT_EMPTY_ARRAY_EX_MESSAGE = "The validated array is empty"; - private static final String DEFAULT_NOT_EMPTY_CHAR_SEQUENCE_EX_MESSAGE = "The validated character sequence is empty"; - private static final String DEFAULT_NOT_EMPTY_COLLECTION_EX_MESSAGE = "The validated collection is empty"; - private static final String DEFAULT_NOT_EMPTY_MAP_EX_MESSAGE = "The validated map is empty"; - private static final String DEFAULT_VALID_INDEX_ARRAY_EX_MESSAGE = "The validated array index is invalid: %d"; - private static final String DEFAULT_VALID_INDEX_CHAR_SEQUENCE_EX_MESSAGE = "The validated character sequence index is invalid: %d"; - private static final String DEFAULT_VALID_INDEX_COLLECTION_EX_MESSAGE = "The validated collection index is invalid: %d"; - private static final String DEFAULT_VALID_STATE_EX_MESSAGE = "The validated state is false"; - private static final String DEFAULT_IS_ASSIGNABLE_EX_MESSAGE = "Cannot assign a %s to a %s"; - private static final String DEFAULT_IS_INSTANCE_OF_EX_MESSAGE = "Expected type: %s, actual: %s"; - - /** - * Constructor. This class should not normally be instantiated. - */ - public Validate() { - } - - // isTrue - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the argument condition is {@code true}; otherwise throwing an - * exception with the specified message. This method is useful when validating - * according to an arbitrary boolean expression, such as validating a primitive - * number or using your own custom validation expression. - *

- * - *
-	 * Validate.isTrue(i > 0.0, "The value must be greater than zero: %d", i);
-	 * 
- * - *

- * For performance reasons, the long value is passed as a separate parameter and - * appended to the exception message only in the case of an error. - *

- * - * @param expression the boolean expression to check - * @param message the {@link String#format(String, Object...)} exception - * message if invalid, not null - * @param value the value to append to the message when invalid - * @throws IllegalArgumentException if expression is {@code false} - * @see #isTrue(boolean) - * @see #isTrue(boolean, String, double) - * @see #isTrue(boolean, String, Object...) - */ - public static void isTrue(final boolean expression, final String message, final long value) { - if (!expression) { - throw new IllegalArgumentException(HString.format(message, Long.valueOf(value))); - } - } - - /** - *

- * Validate that the argument condition is {@code true}; otherwise throwing an - * exception with the specified message. This method is useful when validating - * according to an arbitrary boolean expression, such as validating a primitive - * number or using your own custom validation expression. - *

- * - *
-	 * Validate.isTrue(d > 0.0, "The value must be greater than zero: %s", d);
-	 * 
- * - *

- * For performance reasons, the double value is passed as a separate parameter - * and appended to the exception message only in the case of an error. - *

- * - * @param expression the boolean expression to check - * @param message the {@link String#format(String, Object...)} exception - * message if invalid, not null - * @param value the value to append to the message when invalid - * @throws IllegalArgumentException if expression is {@code false} - * @see #isTrue(boolean) - * @see #isTrue(boolean, String, long) - * @see #isTrue(boolean, String, Object...) - */ - public static void isTrue(final boolean expression, final String message, final double value) { - if (!expression) { - throw new IllegalArgumentException(HString.format(message, Double.valueOf(value))); - } - } - - /** - *

- * Validate that the argument condition is {@code true}; otherwise throwing an - * exception with the specified message. This method is useful when validating - * according to an arbitrary boolean expression, such as validating a primitive - * number or using your own custom validation expression. - *

- * - *
-	 * Validate.isTrue(i >= min && i <= max, "The value must be between %d and %d", min, max);
-	 * Validate.isTrue(myObject.isOk(), "The object is not okay");
-	 * 
- * - * @param expression the boolean expression to check - * @param message the {@link String#format(String, Object...)} exception - * message if invalid, not null - * @param values the optional values for the formatted exception message, - * null array not recommended - * @throws IllegalArgumentException if expression is {@code false} - * @see #isTrue(boolean) - * @see #isTrue(boolean, String, long) - * @see #isTrue(boolean, String, double) - */ - public static void isTrue(final boolean expression, final String message, final Object... values) { - if (!expression) { - throw new IllegalArgumentException(HString.format(message, values)); - } - } - - /** - *

- * Validate that the argument condition is {@code true}; otherwise throwing an - * exception. This method is useful when validating according to an arbitrary - * boolean expression, such as validating a primitive number or using your own - * custom validation expression. - *

- * - *
-	 * Validate.isTrue(i > 0);
-	 * Validate.isTrue(myObject.isOk());
-	 * 
- * - *

- * The message of the exception is "The validated expression is - * false". - *

- * - * @param expression the boolean expression to check - * @throws IllegalArgumentException if expression is {@code false} - * @see #isTrue(boolean, String, long) - * @see #isTrue(boolean, String, double) - * @see #isTrue(boolean, String, Object...) - */ - public static void isTrue(final boolean expression) { - if (!expression) { - throw new IllegalArgumentException(DEFAULT_IS_TRUE_EX_MESSAGE); - } - } - - // notNull - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument is not {@code null}; otherwise throwing - * an exception. - * - *

-	 * Validate.notNull(myObject, "The object must not be null");
-	 * 
- * - *

- * The message of the exception is "The validated object is null". - *

- * - * @param the object type - * @param object the object to check - * @return the validated object (never {@code null} for method chaining) - * @throws NullPointerException if the object is {@code null} - * @see #notNull(Object, String, Object...) - */ - public static T notNull(final T object) { - return notNull(object, DEFAULT_IS_NULL_EX_MESSAGE); - } - - /** - *

- * Validate that the specified argument is not {@code null}; otherwise throwing - * an exception with the specified message. - * - *

-	 * Validate.notNull(myObject, "The object must not be null");
-	 * 
- * - * @param the object type - * @param object the object to check - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message - * @return the validated object (never {@code null} for method chaining) - * @throws NullPointerException if the object is {@code null} - * @see #notNull(Object) - */ - public static T notNull(final T object, final String message, final Object... values) { - return JDKBackports.javaUtilObject_requireNonNull(object, () -> HString.format(message, values)); - } - - // notEmpty array - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument array is neither {@code null} nor a - * length of zero (no elements); otherwise throwing an exception with the - * specified message. - * - *

-	 * Validate.notEmpty(myArray, "The array must not be empty");
-	 * 
- * - * @param the array type - * @param array the array to check, validated not null by this method - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @return the validated array (never {@code null} method for chaining) - * @throws NullPointerException if the array is {@code null} - * @throws IllegalArgumentException if the array is empty - * @see #notEmpty(Object[]) - */ - public static T[] notEmpty(final T[] array, final String message, final Object... values) { - JDKBackports.javaUtilObject_requireNonNull(array, () -> HString.format(message, values)); - if (array.length == 0) { - throw new IllegalArgumentException(HString.format(message, values)); - } - return array; - } - - /** - *

- * Validate that the specified argument array is neither {@code null} nor a - * length of zero (no elements); otherwise throwing an exception. - * - *

-	 * Validate.notEmpty(myArray);
-	 * 
- * - *

- * The message in the exception is "The validated array is empty". - * - * @param the array type - * @param array the array to check, validated not null by this method - * @return the validated array (never {@code null} method for chaining) - * @throws NullPointerException if the array is {@code null} - * @throws IllegalArgumentException if the array is empty - * @see #notEmpty(Object[], String, Object...) - */ - public static T[] notEmpty(final T[] array) { - return notEmpty(array, DEFAULT_NOT_EMPTY_ARRAY_EX_MESSAGE); - } - - // notEmpty collection - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument collection is neither {@code null} nor a - * size of zero (no elements); otherwise throwing an exception with the - * specified message. - * - *

-	 * Validate.notEmpty(myCollection, "The collection must not be empty");
-	 * 
- * - * @param the collection type - * @param collection the collection to check, validated not null by this method - * @param message the {@link String#format(String, Object...)} exception - * message if invalid, not null - * @param values the optional values for the formatted exception message, - * null array not recommended - * @return the validated collection (never {@code null} method for chaining) - * @throws NullPointerException if the collection is {@code null} - * @throws IllegalArgumentException if the collection is empty - * @see #notEmpty(Object[]) - */ - public static > T notEmpty(final T collection, final String message, - final Object... values) { - JDKBackports.javaUtilObject_requireNonNull(collection, () -> HString.format(message, values)); - if (collection.isEmpty()) { - throw new IllegalArgumentException(HString.format(message, values)); - } - return collection; - } - - /** - *

- * Validate that the specified argument collection is neither {@code null} nor a - * size of zero (no elements); otherwise throwing an exception. - * - *

-	 * Validate.notEmpty(myCollection);
-	 * 
- * - *

- * The message in the exception is "The validated collection is - * empty". - *

- * - * @param the collection type - * @param collection the collection to check, validated not null by this method - * @return the validated collection (never {@code null} method for chaining) - * @throws NullPointerException if the collection is {@code null} - * @throws IllegalArgumentException if the collection is empty - * @see #notEmpty(Collection, String, Object...) - */ - public static > T notEmpty(final T collection) { - return notEmpty(collection, DEFAULT_NOT_EMPTY_COLLECTION_EX_MESSAGE); - } - - // notEmpty map - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument map is neither {@code null} nor a size - * of zero (no elements); otherwise throwing an exception with the specified - * message. - * - *

-	 * Validate.notEmpty(myMap, "The map must not be empty");
-	 * 
- * - * @param the map type - * @param map the map to check, validated not null by this method - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @return the validated map (never {@code null} method for chaining) - * @throws NullPointerException if the map is {@code null} - * @throws IllegalArgumentException if the map is empty - * @see #notEmpty(Object[]) - */ - public static > T notEmpty(final T map, final String message, final Object... values) { - JDKBackports.javaUtilObject_requireNonNull(map, () -> HString.format(message, values)); - if (map.isEmpty()) { - throw new IllegalArgumentException(HString.format(message, values)); - } - return map; - } - - /** - *

- * Validate that the specified argument map is neither {@code null} nor a size - * of zero (no elements); otherwise throwing an exception. - * - *

-	 * Validate.notEmpty(myMap);
-	 * 
- * - *

- * The message in the exception is "The validated map is empty". - *

- * - * @param the map type - * @param map the map to check, validated not null by this method - * @return the validated map (never {@code null} method for chaining) - * @throws NullPointerException if the map is {@code null} - * @throws IllegalArgumentException if the map is empty - * @see #notEmpty(Map, String, Object...) - */ - public static > T notEmpty(final T map) { - return notEmpty(map, DEFAULT_NOT_EMPTY_MAP_EX_MESSAGE); - } - - // notEmpty string - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument character sequence is neither - * {@code null} nor a length of zero (no characters); otherwise throwing an - * exception with the specified message. - * - *

-	 * Validate.notEmpty(myString, "The string must not be empty");
-	 * 
- * - * @param the character sequence type - * @param chars the character sequence to check, validated not null by this - * method - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @return the validated character sequence (never {@code null} method for - * chaining) - * @throws NullPointerException if the character sequence is {@code null} - * @throws IllegalArgumentException if the character sequence is empty - * @see #notEmpty(CharSequence) - */ - public static T notEmpty(final T chars, final String message, final Object... values) { - JDKBackports.javaUtilObject_requireNonNull(chars, () -> HString.format(message, values)); - if (chars.length() == 0) { - throw new IllegalArgumentException(HString.format(message, values)); - } - return chars; - } - - /** - *

- * Validate that the specified argument character sequence is neither - * {@code null} nor a length of zero (no characters); otherwise throwing an - * exception with the specified message. - * - *

-	 * Validate.notEmpty(myString);
-	 * 
- * - *

- * The message in the exception is "The validated character sequence is - * empty". - *

- * - * @param the character sequence type - * @param chars the character sequence to check, validated not null by this - * method - * @return the validated character sequence (never {@code null} method for - * chaining) - * @throws NullPointerException if the character sequence is {@code null} - * @throws IllegalArgumentException if the character sequence is empty - * @see #notEmpty(CharSequence, String, Object...) - */ - public static T notEmpty(final T chars) { - return notEmpty(chars, DEFAULT_NOT_EMPTY_CHAR_SEQUENCE_EX_MESSAGE); - } - - // notBlank string - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument character sequence is neither - * {@code null}, a length of zero (no characters), empty nor whitespace; - * otherwise throwing an exception with the specified message. - * - *

-	 * Validate.notBlank(myString, "The string must not be blank");
-	 * 
- * - * @param the character sequence type - * @param chars the character sequence to check, validated not null by this - * method - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @return the validated character sequence (never {@code null} method for - * chaining) - * @throws NullPointerException if the character sequence is {@code null} - * @throws IllegalArgumentException if the character sequence is blank - * @see #notBlank(CharSequence) - * - * @since 3.0 - */ - public static T notBlank(final T chars, final String message, final Object... values) { - JDKBackports.javaUtilObject_requireNonNull(chars, () -> HString.format(message, values)); - if (StringUtils.isBlank(chars)) { - throw new IllegalArgumentException(HString.format(message, values)); - } - return chars; - } - - /** - *

- * Validate that the specified argument character sequence is neither - * {@code null}, a length of zero (no characters), empty nor whitespace; - * otherwise throwing an exception. - * - *

-	 * Validate.notBlank(myString);
-	 * 
- * - *

- * The message in the exception is "The validated character sequence is - * blank". - *

- * - * @param the character sequence type - * @param chars the character sequence to check, validated not null by this - * method - * @return the validated character sequence (never {@code null} method for - * chaining) - * @throws NullPointerException if the character sequence is {@code null} - * @throws IllegalArgumentException if the character sequence is blank - * @see #notBlank(CharSequence, String, Object...) - * - * @since 3.0 - */ - public static T notBlank(final T chars) { - return notBlank(chars, DEFAULT_NOT_BLANK_EX_MESSAGE); - } - - // noNullElements array - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument array is neither {@code null} nor - * contains any elements that are {@code null}; otherwise throwing an exception - * with the specified message. - * - *

-	 * Validate.noNullElements(myArray, "The array contain null at position %d");
-	 * 
- * - *

- * If the array is {@code null}, then the message in the exception is "The - * validated object is null". - *

- * - *

- * If the array has a {@code null} element, then the iteration index of the - * invalid element is appended to the {@code values} argument. - *

- * - * @param the array type - * @param array the array to check, validated not null by this method - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @return the validated array (never {@code null} method for chaining) - * @throws NullPointerException if the array is {@code null} - * @throws IllegalArgumentException if an element is {@code null} - * @see #noNullElements(Object[]) - */ - public static T[] noNullElements(final T[] array, final String message, final Object... values) { - notNull(array); - for (int i = 0; i < array.length; i++) { - if (array[i] == null) { - final Object[] values2 = new Object[values.length + 1]; - System.arraycopy(values, 0, values2, 0, values.length); - values2[values.length - 1] = i; - throw new IllegalArgumentException(HString.format(message, values2)); - } - } - return array; - } - - /** - *

- * Validate that the specified argument array is neither {@code null} nor - * contains any elements that are {@code null}; otherwise throwing an exception. - *

- * - *
-	 * Validate.noNullElements(myArray);
-	 * 
- * - *

- * If the array is {@code null}, then the message in the exception is "The - * validated object is null". - *

- * - *

- * If the array has a {@code null} element, then the message in the exception is - * "The validated array contains null element at index: " followed by - * the index. - *

- * - * @param the array type - * @param array the array to check, validated not null by this method - * @return the validated array (never {@code null} method for chaining) - * @throws NullPointerException if the array is {@code null} - * @throws IllegalArgumentException if an element is {@code null} - * @see #noNullElements(Object[], String, Object...) - */ - public static T[] noNullElements(final T[] array) { - return noNullElements(array, DEFAULT_NO_NULL_ELEMENTS_ARRAY_EX_MESSAGE); - } - - // noNullElements iterable - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument iterable is neither {@code null} nor - * contains any elements that are {@code null}; otherwise throwing an exception - * with the specified message. - * - *

-	 * Validate.noNullElements(myCollection, "The collection contains null at position %d");
-	 * 
- * - *

- * If the iterable is {@code null}, then the message in the exception is - * "The validated object is null". - *

- * - *

- * If the iterable has a {@code null} element, then the iteration index of the - * invalid element is appended to the {@code values} argument. - *

- * - * @param the iterable type - * @param iterable the iterable to check, validated not null by this method - * @param message the {@link String#format(String, Object...)} exception - * message if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @return the validated iterable (never {@code null} method for chaining) - * @throws NullPointerException if the array is {@code null} - * @throws IllegalArgumentException if an element is {@code null} - * @see #noNullElements(Iterable) - */ - public static > T noNullElements(final T iterable, final String message, - final Object... values) { - notNull(iterable); - int i = 0; - for (final Iterator it = iterable.iterator(); it.hasNext(); i++) { - if (it.next() == null) { - final Object[] values2 = new Object[values.length + 1]; - System.arraycopy(values, 0, values2, 0, values.length); - values2[values.length - 1] = i; - throw new IllegalArgumentException(HString.format(message, values2)); - } - } - return iterable; - } - - /** - *

- * Validate that the specified argument iterable is neither {@code null} nor - * contains any elements that are {@code null}; otherwise throwing an exception. - * - *

-	 * Validate.noNullElements(myCollection);
-	 * 
- * - *

- * If the iterable is {@code null}, then the message in the exception is - * "The validated object is null". - *

- * - *

- * If the array has a {@code null} element, then the message in the exception is - * "The validated iterable contains null element at index: " followed - * by the index. - *

- * - * @param the iterable type - * @param iterable the iterable to check, validated not null by this method - * @return the validated iterable (never {@code null} method for chaining) - * @throws NullPointerException if the array is {@code null} - * @throws IllegalArgumentException if an element is {@code null} - * @see #noNullElements(Iterable, String, Object...) - */ - public static > T noNullElements(final T iterable) { - return noNullElements(iterable, DEFAULT_NO_NULL_ELEMENTS_COLLECTION_EX_MESSAGE); - } - - // validIndex array - // --------------------------------------------------------------------------------- - - /** - *

- * Validates that the index is within the bounds of the argument array; - * otherwise throwing an exception with the specified message. - *

- * - *
-	 * Validate.validIndex(myArray, 2, "The array index is invalid: ");
-	 * 
- * - *

- * If the array is {@code null}, then the message of the exception is "The - * validated object is null". - *

- * - * @param the array type - * @param array the array to check, validated not null by this method - * @param index the index to check - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @return the validated array (never {@code null} for method chaining) - * @throws NullPointerException if the array is {@code null} - * @throws IndexOutOfBoundsException if the index is invalid - * @see #validIndex(Object[], int) - * - * @since 3.0 - */ - public static T[] validIndex(final T[] array, final int index, final String message, final Object... values) { - notNull(array); - if (index < 0 || index >= array.length) { - throw new IndexOutOfBoundsException(HString.format(message, values)); - } - return array; - } - - /** - *

- * Validates that the index is within the bounds of the argument array; - * otherwise throwing an exception. - *

- * - *
-	 * Validate.validIndex(myArray, 2);
-	 * 
- * - *

- * If the array is {@code null}, then the message of the exception is "The - * validated object is null". - *

- * - *

- * If the index is invalid, then the message of the exception is "The - * validated array index is invalid: " followed by the index. - *

- * - * @param the array type - * @param array the array to check, validated not null by this method - * @param index the index to check - * @return the validated array (never {@code null} for method chaining) - * @throws NullPointerException if the array is {@code null} - * @throws IndexOutOfBoundsException if the index is invalid - * @see #validIndex(Object[], int, String, Object...) - * - * @since 3.0 - */ - public static T[] validIndex(final T[] array, final int index) { - return validIndex(array, index, DEFAULT_VALID_INDEX_ARRAY_EX_MESSAGE, Integer.valueOf(index)); - } - - // validIndex collection - // --------------------------------------------------------------------------------- - - /** - *

- * Validates that the index is within the bounds of the argument collection; - * otherwise throwing an exception with the specified message. - *

- * - *
-	 * Validate.validIndex(myCollection, 2, "The collection index is invalid: ");
-	 * 
- * - *

- * If the collection is {@code null}, then the message of the exception is - * "The validated object is null". - *

- * - * @param the collection type - * @param collection the collection to check, validated not null by this method - * @param index the index to check - * @param message the {@link String#format(String, Object...)} exception - * message if invalid, not null - * @param values the optional values for the formatted exception message, - * null array not recommended - * @return the validated collection (never {@code null} for chaining) - * @throws NullPointerException if the collection is {@code null} - * @throws IndexOutOfBoundsException if the index is invalid - * @see #validIndex(Collection, int) - * - * @since 3.0 - */ - public static > T validIndex(final T collection, final int index, final String message, - final Object... values) { - notNull(collection); - if (index < 0 || index >= collection.size()) { - throw new IndexOutOfBoundsException(HString.format(message, values)); - } - return collection; - } - - /** - *

- * Validates that the index is within the bounds of the argument collection; - * otherwise throwing an exception. - *

- * - *
-	 * Validate.validIndex(myCollection, 2);
-	 * 
- * - *

- * If the index is invalid, then the message of the exception is "The - * validated collection index is invalid: " followed by the index. - *

- * - * @param the collection type - * @param collection the collection to check, validated not null by this method - * @param index the index to check - * @return the validated collection (never {@code null} for method chaining) - * @throws NullPointerException if the collection is {@code null} - * @throws IndexOutOfBoundsException if the index is invalid - * @see #validIndex(Collection, int, String, Object...) - * - * @since 3.0 - */ - public static > T validIndex(final T collection, final int index) { - return validIndex(collection, index, DEFAULT_VALID_INDEX_COLLECTION_EX_MESSAGE, Integer.valueOf(index)); - } - - // validIndex string - // --------------------------------------------------------------------------------- - - /** - *

- * Validates that the index is within the bounds of the argument character - * sequence; otherwise throwing an exception with the specified message. - *

- * - *
-	 * Validate.validIndex(myStr, 2, "The string index is invalid: ");
-	 * 
- * - *

- * If the character sequence is {@code null}, then the message of the exception - * is "The validated object is null". - *

- * - * @param the character sequence type - * @param chars the character sequence to check, validated not null by this - * method - * @param index the index to check - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @return the validated character sequence (never {@code null} for method - * chaining) - * @throws NullPointerException if the character sequence is {@code null} - * @throws IndexOutOfBoundsException if the index is invalid - * @see #validIndex(CharSequence, int) - * - * @since 3.0 - */ - public static T validIndex(final T chars, final int index, final String message, - final Object... values) { - notNull(chars); - if (index < 0 || index >= chars.length()) { - throw new IndexOutOfBoundsException(HString.format(message, values)); - } - return chars; - } - - /** - *

- * Validates that the index is within the bounds of the argument character - * sequence; otherwise throwing an exception. - *

- * - *
-	 * Validate.validIndex(myStr, 2);
-	 * 
- * - *

- * If the character sequence is {@code null}, then the message of the exception - * is "The validated object is null". - *

- * - *

- * If the index is invalid, then the message of the exception is "The - * validated character sequence index is invalid: " followed by the index. - *

- * - * @param the character sequence type - * @param chars the character sequence to check, validated not null by this - * method - * @param index the index to check - * @return the validated character sequence (never {@code null} for method - * chaining) - * @throws NullPointerException if the character sequence is {@code null} - * @throws IndexOutOfBoundsException if the index is invalid - * @see #validIndex(CharSequence, int, String, Object...) - * - * @since 3.0 - */ - public static T validIndex(final T chars, final int index) { - return validIndex(chars, index, DEFAULT_VALID_INDEX_CHAR_SEQUENCE_EX_MESSAGE, Integer.valueOf(index)); - } - - // validState - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the stateful condition is {@code true}; otherwise throwing an - * exception. This method is useful when validating according to an arbitrary - * boolean expression, such as validating a primitive number or using your own - * custom validation expression. - *

- * - *
-	 * Validate.validState(field > 0);
-	 * Validate.validState(this.isOk());
-	 * 
- * - *

- * The message of the exception is "The validated state is false". - *

- * - * @param expression the boolean expression to check - * @throws IllegalStateException if expression is {@code false} - * @see #validState(boolean, String, Object...) - * - * @since 3.0 - */ - public static void validState(final boolean expression) { - if (!expression) { - throw new IllegalStateException(DEFAULT_VALID_STATE_EX_MESSAGE); - } - } - - /** - *

- * Validate that the stateful condition is {@code true}; otherwise throwing an - * exception with the specified message. This method is useful when validating - * according to an arbitrary boolean expression, such as validating a primitive - * number or using your own custom validation expression. - *

- * - *
-	 * Validate.validState(this.isOk(), "The state is not OK: %s", myObject);
-	 * 
- * - * @param expression the boolean expression to check - * @param message the {@link String#format(String, Object...)} exception - * message if invalid, not null - * @param values the optional values for the formatted exception message, - * null array not recommended - * @throws IllegalStateException if expression is {@code false} - * @see #validState(boolean) - * - * @since 3.0 - */ - public static void validState(final boolean expression, final String message, final Object... values) { - if (!expression) { - throw new IllegalStateException(HString.format(message, values)); - } - } - - // matchesPattern - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument character sequence matches the specified - * regular expression pattern; otherwise throwing an exception. - *

- * - *
-	 * Validate.matchesPattern("hi", "[a-z]*");
-	 * 
- * - *

- * The syntax of the pattern is the one used in the {@link Pattern} class. - *

- * - * @param input the character sequence to validate, not null - * @param pattern the regular expression pattern, not null - * @throws IllegalArgumentException if the character sequence does not match the - * pattern - * @see #matchesPattern(CharSequence, String, String, Object...) - * - * @since 3.0 - */ - public static void matchesPattern(final CharSequence input, final String pattern) { - // TODO when breaking BC, consider returning input - if (!Pattern.matches(pattern, input)) { - throw new IllegalArgumentException(HString.format(DEFAULT_MATCHES_PATTERN_EX, input, pattern)); - } - } - - /** - *

- * Validate that the specified argument character sequence matches the specified - * regular expression pattern; otherwise throwing an exception with the - * specified message. - *

- * - *
-	 * Validate.matchesPattern("hi", "[a-z]*", "%s does not match %s", "hi" "[a-z]*");
-	 * 
- * - *

- * The syntax of the pattern is the one used in the {@link Pattern} class. - *

- * - * @param input the character sequence to validate, not null - * @param pattern the regular expression pattern, not null - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @throws IllegalArgumentException if the character sequence does not match the - * pattern - * @see #matchesPattern(CharSequence, String) - * - * @since 3.0 - */ - public static void matchesPattern(final CharSequence input, final String pattern, final String message, - final Object... values) { - // TODO when breaking BC, consider returning input - if (!Pattern.matches(pattern, input)) { - throw new IllegalArgumentException(HString.format(message, values)); - } - } - - // notNaN - // --------------------------------------------------------------------------------- - - /** - *

- * Validates that the specified argument is not {@code NaN}; otherwise throwing - * an exception. - *

- * - *
-	 * Validate.notNaN(myDouble);
-	 * 
- * - *

- * The message of the exception is "The validated value is not a - * number". - *

- * - * @param value the value to validate - * @throws IllegalArgumentException if the value is not a number - * @see #notNaN(double, java.lang.String, java.lang.Object...) - * - * @since 3.5 - */ - public static void notNaN(final double value) { - notNaN(value, DEFAULT_NOT_NAN_EX_MESSAGE); - } - - /** - *

- * Validates that the specified argument is not {@code NaN}; otherwise throwing - * an exception with the specified message. - *

- * - *
-	 * Validate.notNaN(myDouble, "The value must be a number");
-	 * 
- * - * @param value the value to validate - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message - * @throws IllegalArgumentException if the value is not a number - * @see #notNaN(double) - * - * @since 3.5 - */ - public static void notNaN(final double value, final String message, final Object... values) { - if (Double.isNaN(value)) { - throw new IllegalArgumentException(HString.format(message, values)); - } - } - - // finite - // --------------------------------------------------------------------------------- - - /** - *

- * Validates that the specified argument is not infinite or {@code NaN}; - * otherwise throwing an exception. - *

- * - *
-	 * Validate.finite(myDouble);
-	 * 
- * - *

- * The message of the exception is "The value is invalid: %f". - *

- * - * @param value the value to validate - * @throws IllegalArgumentException if the value is infinite or {@code NaN} - * @see #finite(double, java.lang.String, java.lang.Object...) - * - * @since 3.5 - */ - public static void finite(final double value) { - finite(value, DEFAULT_FINITE_EX_MESSAGE, value); - } - - /** - *

- * Validates that the specified argument is not infinite or {@code NaN}; - * otherwise throwing an exception with the specified message. - *

- * - *
-	 * Validate.finite(myDouble, "The argument must contain a numeric value");
-	 * 
- * - * @param value the value to validate - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message - * @throws IllegalArgumentException if the value is infinite or {@code NaN} - * @see #finite(double) - * - * @since 3.5 - */ - public static void finite(final double value, final String message, final Object... values) { - if (Double.isNaN(value) || Double.isInfinite(value)) { - throw new IllegalArgumentException(HString.format(message, values)); - } - } - - // inclusiveBetween - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument object fall between the two inclusive - * values specified; otherwise, throws an exception. - *

- * - *
-	 * Validate.inclusiveBetween(0, 2, 1);
-	 * 
- * - * @param the type of the argument object - * @param start the inclusive start value, not null - * @param end the inclusive end value, not null - * @param value the object to validate, not null - * @throws IllegalArgumentException if the value falls outside the boundaries - * @see #inclusiveBetween(Object, Object, Comparable, String, Object...) - * - * @since 3.0 - */ - public static void inclusiveBetween(final T start, final T end, final Comparable value) { - // TODO when breaking BC, consider returning value - if (value.compareTo(start) < 0 || value.compareTo(end) > 0) { - throw new IllegalArgumentException(HString.format(DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); - } - } - - /** - *

- * Validate that the specified argument object fall between the two inclusive - * values specified; otherwise, throws an exception with the specified message. - *

- * - *
-	 * Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");
-	 * 
- * - * @param the type of the argument object - * @param start the inclusive start value, not null - * @param end the inclusive end value, not null - * @param value the object to validate, not null - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @throws IllegalArgumentException if the value falls outside the boundaries - * @see #inclusiveBetween(Object, Object, Comparable) - * - * @since 3.0 - */ - public static void inclusiveBetween(final T start, final T end, final Comparable value, final String message, - final Object... values) { - // TODO when breaking BC, consider returning value - if (value.compareTo(start) < 0 || value.compareTo(end) > 0) { - throw new IllegalArgumentException(HString.format(message, values)); - } - } - - /** - * Validate that the specified primitive value falls between the two inclusive - * values specified; otherwise, throws an exception. - * - *
-	 * Validate.inclusiveBetween(0, 2, 1);
-	 * 
- * - * @param start the inclusive start value - * @param end the inclusive end value - * @param value the value to validate - * @throws IllegalArgumentException if the value falls outside the boundaries - * (inclusive) - * - * @since 3.3 - */ - @SuppressWarnings("boxing") - public static void inclusiveBetween(final long start, final long end, final long value) { - // TODO when breaking BC, consider returning value - if (value < start || value > end) { - throw new IllegalArgumentException(HString.format(DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); - } - } - - /** - * Validate that the specified primitive value falls between the two inclusive - * values specified; otherwise, throws an exception with the specified message. - * - *
-	 * Validate.inclusiveBetween(0, 2, 1, "Not in range");
-	 * 
- * - * @param start the inclusive start value - * @param end the inclusive end value - * @param value the value to validate - * @param message the exception message if invalid, not null - * - * @throws IllegalArgumentException if the value falls outside the boundaries - * - * @since 3.3 - */ - public static void inclusiveBetween(final long start, final long end, final long value, final String message) { - // TODO when breaking BC, consider returning value - if (value < start || value > end) { - throw new IllegalArgumentException(message); - } - } - - /** - * Validate that the specified primitive value falls between the two inclusive - * values specified; otherwise, throws an exception. - * - *
-	 * Validate.inclusiveBetween(0.1, 2.1, 1.1);
-	 * 
- * - * @param start the inclusive start value - * @param end the inclusive end value - * @param value the value to validate - * @throws IllegalArgumentException if the value falls outside the boundaries - * (inclusive) - * - * @since 3.3 - */ - @SuppressWarnings("boxing") - public static void inclusiveBetween(final double start, final double end, final double value) { - // TODO when breaking BC, consider returning value - if (value < start || value > end) { - throw new IllegalArgumentException(HString.format(DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); - } - } - - /** - * Validate that the specified primitive value falls between the two inclusive - * values specified; otherwise, throws an exception with the specified message. - * - *
-	 * Validate.inclusiveBetween(0.1, 2.1, 1.1, "Not in range");
-	 * 
- * - * @param start the inclusive start value - * @param end the inclusive end value - * @param value the value to validate - * @param message the exception message if invalid, not null - * - * @throws IllegalArgumentException if the value falls outside the boundaries - * - * @since 3.3 - */ - public static void inclusiveBetween(final double start, final double end, final double value, - final String message) { - // TODO when breaking BC, consider returning value - if (value < start || value > end) { - throw new IllegalArgumentException(message); - } - } - - // exclusiveBetween - // --------------------------------------------------------------------------------- - - /** - *

- * Validate that the specified argument object fall between the two exclusive - * values specified; otherwise, throws an exception. - *

- * - *
-	 * Validate.exclusiveBetween(0, 2, 1);
-	 * 
- * - * @param the type of the argument object - * @param start the exclusive start value, not null - * @param end the exclusive end value, not null - * @param value the object to validate, not null - * @throws IllegalArgumentException if the value falls outside the boundaries - * @see #exclusiveBetween(Object, Object, Comparable, String, Object...) - * - * @since 3.0 - */ - public static void exclusiveBetween(final T start, final T end, final Comparable value) { - // TODO when breaking BC, consider returning value - if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) { - throw new IllegalArgumentException(HString.format(DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); - } - } - - /** - *

- * Validate that the specified argument object fall between the two exclusive - * values specified; otherwise, throws an exception with the specified message. - *

- * - *
-	 * Validate.exclusiveBetween(0, 2, 1, "Not in boundaries");
-	 * 
- * - * @param the type of the argument object - * @param start the exclusive start value, not null - * @param end the exclusive end value, not null - * @param value the object to validate, not null - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @throws IllegalArgumentException if the value falls outside the boundaries - * @see #exclusiveBetween(Object, Object, Comparable) - * - * @since 3.0 - */ - public static void exclusiveBetween(final T start, final T end, final Comparable value, final String message, - final Object... values) { - // TODO when breaking BC, consider returning value - if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) { - throw new IllegalArgumentException(HString.format(message, values)); - } - } - - /** - * Validate that the specified primitive value falls between the two exclusive - * values specified; otherwise, throws an exception. - * - *
-	 * Validate.exclusiveBetween(0, 2, 1);
-	 * 
- * - * @param start the exclusive start value - * @param end the exclusive end value - * @param value the value to validate - * @throws IllegalArgumentException if the value falls out of the boundaries - * - * @since 3.3 - */ - @SuppressWarnings("boxing") - public static void exclusiveBetween(final long start, final long end, final long value) { - // TODO when breaking BC, consider returning value - if (value <= start || value >= end) { - throw new IllegalArgumentException(HString.format(DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); - } - } - - /** - * Validate that the specified primitive value falls between the two exclusive - * values specified; otherwise, throws an exception with the specified message. - * - *
-	 * Validate.exclusiveBetween(0, 2, 1, "Not in range");
-	 * 
- * - * @param start the exclusive start value - * @param end the exclusive end value - * @param value the value to validate - * @param message the exception message if invalid, not null - * - * @throws IllegalArgumentException if the value falls outside the boundaries - * - * @since 3.3 - */ - public static void exclusiveBetween(final long start, final long end, final long value, final String message) { - // TODO when breaking BC, consider returning value - if (value <= start || value >= end) { - throw new IllegalArgumentException(message); - } - } - - /** - * Validate that the specified primitive value falls between the two exclusive - * values specified; otherwise, throws an exception. - * - *
-	 * Validate.exclusiveBetween(0.1, 2.1, 1.1);
-	 * 
- * - * @param start the exclusive start value - * @param end the exclusive end value - * @param value the value to validate - * @throws IllegalArgumentException if the value falls out of the boundaries - * - * @since 3.3 - */ - @SuppressWarnings("boxing") - public static void exclusiveBetween(final double start, final double end, final double value) { - // TODO when breaking BC, consider returning value - if (value <= start || value >= end) { - throw new IllegalArgumentException(HString.format(DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); - } - } - - /** - * Validate that the specified primitive value falls between the two exclusive - * values specified; otherwise, throws an exception with the specified message. - * - *
-	 * Validate.exclusiveBetween(0.1, 2.1, 1.1, "Not in range");
-	 * 
- * - * @param start the exclusive start value - * @param end the exclusive end value - * @param value the value to validate - * @param message the exception message if invalid, not null - * - * @throws IllegalArgumentException if the value falls outside the boundaries - * - * @since 3.3 - */ - public static void exclusiveBetween(final double start, final double end, final double value, - final String message) { - // TODO when breaking BC, consider returning value - if (value <= start || value >= end) { - throw new IllegalArgumentException(message); - } - } - - // isInstanceOf - // --------------------------------------------------------------------------------- - - /** - * Validates that the argument is an instance of the specified class, if not - * throws an exception. - * - *

- * This method is useful when validating according to an arbitrary class - *

- * - *
-	 * Validate.isInstanceOf(OkClass.class, object);
-	 * 
- * - *

- * The message of the exception is "Expected type: {type}, actual: - * {obj_type}" - *

- * - * @param type the class the object must be validated against, not null - * @param obj the object to check, null throws an exception - * @throws IllegalArgumentException if argument is not of specified class - * @see #isInstanceOf(Class, Object, String, Object...) - * - * @since 3.0 - */ - public static void isInstanceOf(final Class type, final Object obj) { - // TODO when breaking BC, consider returning obj - if (!type.isInstance(obj)) { - throw new IllegalArgumentException(HString.format(DEFAULT_IS_INSTANCE_OF_EX_MESSAGE, type.getName(), - obj == null ? "null" : obj.getClass().getName())); - } - } - - /** - *

- * Validate that the argument is an instance of the specified class; otherwise - * throwing an exception with the specified message. This method is useful when - * validating according to an arbitrary class - *

- * - *
-	 * Validate.isInstanceOf(OkClass.class, object, "Wrong class, object is of class %s", object.getClass().getName());
-	 * 
- * - * @param type the class the object must be validated against, not null - * @param obj the object to check, null throws an exception - * @param message the {@link String#format(String, Object...)} exception message - * if invalid, not null - * @param values the optional values for the formatted exception message, null - * array not recommended - * @throws IllegalArgumentException if argument is not of specified class - * @see #isInstanceOf(Class, Object) - * - * @since 3.0 - */ - public static void isInstanceOf(final Class type, final Object obj, final String message, - final Object... values) { - // TODO when breaking BC, consider returning obj - if (!type.isInstance(obj)) { - throw new IllegalArgumentException(HString.format(message, values)); - } - } - - // isAssignableFrom - // --------------------------------------------------------------------------------- - - /** - * Validates that the argument can be converted to the specified class, if not, - * throws an exception. - * - *

- * This method is useful when validating that there will be no casting errors. - *

- * - *
-	 * Validate.isAssignableFrom(SuperClass.class, object.getClass());
-	 * 
- * - *

- * The message format of the exception is "Cannot assign {type} to - * {superType}" - *

- * - * @param superType the class the class must be validated against, not null - * @param type the class to check, not null - * @throws IllegalArgumentException if type argument is not assignable to the - * specified superType - * @see #isAssignableFrom(Class, Class, String, Object...) - * - * @since 3.0 - */ - public static void isAssignableFrom(final Class superType, final Class type) { - // TODO when breaking BC, consider returning type - if (!superType.isAssignableFrom(type)) { - throw new IllegalArgumentException(HString.format(DEFAULT_IS_ASSIGNABLE_EX_MESSAGE, - type == null ? "null" : type.getName(), superType.getName())); - } - } - - /** - * Validates that the argument can be converted to the specified class, if not - * throws an exception. - * - *

- * This method is useful when validating if there will be no casting errors. - *

- * - *
-	 * Validate.isAssignableFrom(SuperClass.class, object.getClass());
-	 * 
- * - *

- * The message of the exception is "The validated object can not be - * converted to the" followed by the name of the class and - * "class" - *

- * - * @param superType the class the class must be validated against, not null - * @param type the class to check, not null - * @param message the {@link String#format(String, Object...)} exception - * message if invalid, not null - * @param values the optional values for the formatted exception message, - * null array not recommended - * @throws IllegalArgumentException if argument can not be converted to the - * specified class - * @see #isAssignableFrom(Class, Class) - */ - public static void isAssignableFrom(final Class superType, final Class type, final String message, - final Object... values) { - // TODO when breaking BC, consider returning type - if (!superType.isAssignableFrom(type)) { - throw new IllegalArgumentException(HString.format(message, values)); - } - } -} diff --git a/sources/main/java/org/apache/commons/lang3/arch/Processor.java b/sources/main/java/org/apache/commons/lang3/arch/Processor.java deleted file mode 100644 index 148a9dfe..00000000 --- a/sources/main/java/org/apache/commons/lang3/arch/Processor.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.arch; - -/** - * The {@link Processor} represents a microprocessor and defines some properties - * like architecture and type of the microprocessor. - * - * @since 3.6 - */ -public class Processor { - - /** - * The {@link Arch} enum defines the architecture of a microprocessor. The - * architecture represents the bit value of the microprocessor. The following - * architectures are defined: - *
    - *
  • 32-bit
  • - *
  • 64-bit
  • - *
  • Unknown
  • - *
- */ - public enum Arch { - - /** - * A 32-bit processor architecture. - */ - BIT_32("32-bit"), - - /** - * A 64-bit processor architecture. - */ - BIT_64("64-bit"), - - /** - * An unknown-bit processor architecture. - */ - UNKNOWN("Unknown"); - - /** - * A label suitable for display. - * - * @since 3.10 - */ - private final String label; - - Arch(final String label) { - this.label = label; - } - - /** - * Gets the label suitable for display. - * - * @return the label. - */ - public String getLabel() { - return label; - } - } - - /** - * The {@link Type} enum defines types of a microprocessor. The following types - * are defined: - *
    - *
  • x86
  • - *
  • ia64
  • - *
  • PPC
  • - *
  • Unknown
  • - *
- */ - public enum Type { - - /** - * Intel x86 series of instruction set architectures. - */ - X86, - - /** - * Intel Itanium 64-bit architecture. - */ - IA_64, - - /** - * Apple–IBM–Motorola PowerPC architecture. - */ - PPC, - - /** - * Unknown architecture. - */ - UNKNOWN - } - - private final Arch arch; - private final Type type; - - /** - * Constructs a {@link Processor} object with the given parameters. - * - * @param arch The processor architecture. - * @param type The processor type. - */ - public Processor(final Arch arch, final Type type) { - this.arch = arch; - this.type = type; - } - - /** - * Returns the processor architecture as an {@link Arch} enum. The processor - * architecture defines, if the processor has a 32 or 64 bit architecture. - * - * @return A {@link Arch} enum. - */ - public Arch getArch() { - return arch; - } - - /** - * Returns the processor type as {@link Type} enum. The processor type defines, - * if the processor is for example a x86 or PPA. - * - * @return A {@link Type} enum. - */ - public Type getType() { - return type; - } - - /** - * Checks if {@link Processor} is 32 bit. - * - * @return {@code true}, if {@link Processor} is {@link Arch#BIT_32}, else - * {@code false}. - */ - public boolean is32Bit() { - return Arch.BIT_32 == arch; - } - - /** - * Checks if {@link Processor} is 64 bit. - * - * @return {@code true}, if {@link Processor} is {@link Arch#BIT_64}, else - * {@code false}. - */ - public boolean is64Bit() { - return Arch.BIT_64 == arch; - } - - /** - * Checks if {@link Processor} is type of x86. - * - * @return {@code true}, if {@link Processor} is {@link Type#X86}, else - * {@code false}. - */ - public boolean isX86() { - return Type.X86 == type; - } - - /** - * Checks if {@link Processor} is type of Intel Itanium. - * - * @return {@code true}. if {@link Processor} is {@link Type#IA_64}, else - * {@code false}. - */ - public boolean isIA64() { - return Type.IA_64 == type; - } - - /** - * Checks if {@link Processor} is type of Power PC. - * - * @return {@code true}. if {@link Processor} is {@link Type#PPC}, else - * {@code false}. - */ - public boolean isPPC() { - return Type.PPC == type; - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/arch/package-info.java b/sources/main/java/org/apache/commons/lang3/arch/package-info.java deleted file mode 100644 index e340e495..00000000 --- a/sources/main/java/org/apache/commons/lang3/arch/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Provides classes to work with the values of the os.arch system property. - * - * @since 3.6 - */ -package org.apache.commons.lang3.arch; diff --git a/sources/main/java/org/apache/commons/lang3/builder/Builder.java b/sources/main/java/org/apache/commons/lang3/builder/Builder.java deleted file mode 100644 index 1e79d7ab..00000000 --- a/sources/main/java/org/apache/commons/lang3/builder/Builder.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.builder; - -/** - *

- * The Builder interface is designed to designate a class as a builder - * object in the Builder design pattern. Builders are capable of creating and - * configuring objects or results that normally take multiple steps to construct - * or are very complex to derive. - *

- * - *

- * The builder interface defines a single method, {@link #build()}, that classes - * must implement. The result of this method should be the final configured - * object or result after all building operations are performed. - *

- * - *

- * It is a recommended practice that the methods supplied to configure the - * object or result being built return a reference to {@code this} so that - * method calls can be chained together. - *

- * - *

- * Example Builder: - * - *

- * 
- * class FontBuilder implements Builder<Font> {
- *     private Font font;
- *
- *     public FontBuilder(String fontName) {
- *         this.font = new Font(fontName, Font.PLAIN, 12);
- *     }
- *
- *     public FontBuilder bold() {
- *         this.font = this.font.deriveFont(Font.BOLD);
- *         return this; // Reference returned so calls can be chained
- *     }
- *
- *     public FontBuilder size(float pointSize) {
- *         this.font = this.font.deriveFont(pointSize);
- *         return this; // Reference returned so calls can be chained
- *     }
- *
- *     // Other Font construction methods
- *
- *     public Font build() {
- *         return this.font;
- *     }
- * }
- * 
- * 
- * - * Example Builder Usage: - * - *
- * 
- * Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
- *                                                              .size(14.0f)
- *                                                              .build();
- * 
- * 
- * - * - * @param the type of object that the builder will construct or compute. - * - * @since 3.0 - */ -@FunctionalInterface -public interface Builder { - - /** - * Returns a reference to the object being constructed or result being - * calculated by the builder. - * - * @return the object constructed or result calculated by the builder. - */ - T build(); -} diff --git a/sources/main/java/org/apache/commons/lang3/builder/ToStringBuilder.java b/sources/main/java/org/apache/commons/lang3/builder/ToStringBuilder.java deleted file mode 100644 index 2a5b6f1f..00000000 --- a/sources/main/java/org/apache/commons/lang3/builder/ToStringBuilder.java +++ /dev/null @@ -1,1138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.builder; - -import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.Validate; - -/** - *

- * Assists in implementing {@link Object#toString()} methods. - *

- * - *

- * This class enables a good and consistent {@code toString()} to be built for - * any class or object. This class aims to simplify the process by: - *

- *
    - *
  • allowing field names
  • - *
  • handling all types consistently
  • - *
  • handling nulls consistently
  • - *
  • outputting arrays and multi-dimensional arrays
  • - *
  • enabling the detail level to be controlled for Objects and - * Collections
  • - *
  • handling class hierarchies
  • - *
- * - *

- * To use this class write code as follows: - *

- * - *
- * public class Person {
- *   String name;
- *   int age;
- *   boolean smoker;
- *
- *   ...
- *
- *   public String toString() {
- *     return new ToStringBuilder(this).
- *       append("name", name).
- *       append("age", age).
- *       append("smoker", smoker).
- *       toString();
- *   }
- * }
- * 
- * - *

- * This will produce a toString of the format: - * {@code Person@7f54[name=Stephen,age=29,smoker=false]} - *

- * - *

- * To add the superclass {@code toString}, use {@link #appendSuper}. To append - * the {@code toString} from an object that is delegated to (or any other - * object), use {@link #appendToString}. - *

- * - *

- * Alternatively, there is a method that uses reflection to determine the fields - * to test. Because these fields are usually private, the method, - * {@code reflectionToString}, uses {@code AccessibleObject.setAccessible} to - * change the visibility of the fields. This will fail under a security manager, - * unless the appropriate permissions are set up correctly. It is also slower - * than testing explicitly. - *

- * - *

- * A typical invocation for this method would look like: - *

- * - *
- * public String toString() {
- * 	return ToStringBuilder.reflectionToString(this);
- * }
- * 
- * - *

- * You can also use the builder to debug 3rd party objects: - *

- * - *
- * System.out.println("An object: " + ToStringBuilder.reflectionToString(anObject));
- * 
- * - *

- * The exact format of the {@code toString} is determined by the - * {@link ToStringStyle} passed into the constructor. - *

- * - * @since 1.0 - */ -public class ToStringBuilder implements Builder { - - /** - * The default style of output to use, not null. - */ - private static volatile ToStringStyle defaultStyle = ToStringStyle.DEFAULT_STYLE; - - // ---------------------------------------------------------------------------- - - /** - *

- * Gets the default {@code ToStringStyle} to use. - *

- * - *

- * This method gets a singleton default value, typically for the whole JVM. - * Changing this default should generally only be done during application - * startup. It is recommended to pass a {@code ToStringStyle} to the constructor - * instead of using this global default. - *

- * - *

- * This method can be used from multiple threads. Internally, a {@code volatile} - * variable is used to provide the guarantee that the latest value set using - * {@link #setDefaultStyle} is the value returned. It is strongly recommended - * that the default style is only changed during application startup. - *

- * - *

- * One reason for changing the default could be to have a verbose style during - * development and a compact style in production. - *

- * - * @return the default {@code ToStringStyle}, never null - */ - public static ToStringStyle getDefaultStyle() { - return defaultStyle; - } - - /** - *

- * Sets the default {@code ToStringStyle} to use. - *

- * - *

- * This method sets a singleton default value, typically for the whole JVM. - * Changing this default should generally only be done during application - * startup. It is recommended to pass a {@code ToStringStyle} to the constructor - * instead of changing this global default. - *

- * - *

- * This method is not intended for use from multiple threads. Internally, a - * {@code volatile} variable is used to provide the guarantee that the latest - * value set is the value returned from {@link #getDefaultStyle}. - *

- * - * @param style the default {@code ToStringStyle} - * @throws IllegalArgumentException if the style is {@code null} - */ - public static void setDefaultStyle(final ToStringStyle style) { - defaultStyle = Validate.notNull(style, "style"); - } - - // ---------------------------------------------------------------------------- - - /** - * Current toString buffer, not null. - */ - private final StringBuffer buffer; - /** - * The object being output, may be null. - */ - private final Object object; - /** - * The style of output to use, not null. - */ - private final ToStringStyle style; - - /** - *

- * Constructs a builder for the specified object using the default output style. - *

- * - *

- * This default style is obtained from {@link #getDefaultStyle()}. - *

- * - * @param object the Object to build a {@code toString} for, not recommended to - * be null - */ - public ToStringBuilder(final Object object) { - this(object, null, null); - } - - /** - *

- * Constructs a builder for the specified object using the defined output style. - *

- * - *

- * If the style is {@code null}, the default style is used. - *

- * - * @param object the Object to build a {@code toString} for, not recommended to - * be null - * @param style the style of the {@code toString} to create, null uses the - * default style - */ - public ToStringBuilder(final Object object, final ToStringStyle style) { - this(object, style, null); - } - - /** - *

- * Constructs a builder for the specified object. - *

- * - *

- * If the style is {@code null}, the default style is used. - *

- * - *

- * If the buffer is {@code null}, a new one is created. - *

- * - * @param object the Object to build a {@code toString} for, not recommended to - * be null - * @param style the style of the {@code toString} to create, null uses the - * default style - * @param buffer the {@code StringBuffer} to populate, may be null - */ - public ToStringBuilder(final Object object, ToStringStyle style, StringBuffer buffer) { - if (style == null) { - style = getDefaultStyle(); - } - if (buffer == null) { - buffer = new StringBuffer(512); - } - this.buffer = buffer; - this.style = style; - this.object = object; - - style.appendStart(buffer, object); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code boolean} value. - *

- * - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final boolean value) { - style.append(buffer, null, value); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code boolean} array. - *

- * - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final boolean[] array) { - style.append(buffer, null, array, null); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code byte} value. - *

- * - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final byte value) { - style.append(buffer, null, value); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code byte} array. - *

- * - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final byte[] array) { - style.append(buffer, null, array, null); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code char} value. - *

- * - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final char value) { - style.append(buffer, null, value); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code char} array. - *

- * - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final char[] array) { - style.append(buffer, null, array, null); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code double} value. - *

- * - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final double value) { - style.append(buffer, null, value); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code double} array. - *

- * - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final double[] array) { - style.append(buffer, null, array, null); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code float} value. - *

- * - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final float value) { - style.append(buffer, null, value); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code float} array. - *

- * - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final float[] array) { - style.append(buffer, null, array, null); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} an {@code int} value. - *

- * - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final int value) { - style.append(buffer, null, value); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} an {@code int} array. - *

- * - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final int[] array) { - style.append(buffer, null, array, null); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code long} value. - *

- * - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final long value) { - style.append(buffer, null, value); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code long} array. - *

- * - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final long[] array) { - style.append(buffer, null, array, null); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} an {@code Object} value. - *

- * - * @param obj the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final Object obj) { - style.append(buffer, null, obj, null); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} an {@code Object} array. - *

- * - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final Object[] array) { - style.append(buffer, null, array, null); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code short} value. - *

- * - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final short value) { - style.append(buffer, null, value); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code short} array. - *

- * - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final short[] array) { - style.append(buffer, null, array, null); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code boolean} value. - *

- * - * @param fieldName the field name - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final boolean value) { - style.append(buffer, fieldName, value); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code boolean} array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code hashCode} - * @return this - */ - public ToStringBuilder append(final String fieldName, final boolean[] array) { - style.append(buffer, fieldName, array, null); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code boolean} array. - *

- * - *

- * A boolean parameter controls the level of detail to show. Setting - * {@code true} will output the array in full. Setting {@code false} will output - * a summary, typically the size of the array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info - * @return this - */ - public ToStringBuilder append(final String fieldName, final boolean[] array, final boolean fullDetail) { - style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); - return this; - } - - /** - *

- * Append to the {@code toString} an {@code byte} value. - *

- * - * @param fieldName the field name - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final byte value) { - style.append(buffer, fieldName, value); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code byte} array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final byte[] array) { - style.append(buffer, fieldName, array, null); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code byte} array. - *

- * - *

- * A boolean parameter controls the level of detail to show. Setting - * {@code true} will output the array in full. Setting {@code false} will output - * a summary, typically the size of the array. - * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info - * @return this - */ - public ToStringBuilder append(final String fieldName, final byte[] array, final boolean fullDetail) { - style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code char} value. - *

- * - * @param fieldName the field name - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final char value) { - style.append(buffer, fieldName, value); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code char} array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final char[] array) { - style.append(buffer, fieldName, array, null); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code char} array. - *

- * - *

- * A boolean parameter controls the level of detail to show. Setting - * {@code true} will output the array in full. Setting {@code false} will output - * a summary, typically the size of the array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info - * @return this - */ - public ToStringBuilder append(final String fieldName, final char[] array, final boolean fullDetail) { - style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code double} value. - *

- * - * @param fieldName the field name - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final double value) { - style.append(buffer, fieldName, value); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code double} array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final double[] array) { - style.append(buffer, fieldName, array, null); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code double} array. - *

- * - *

- * A boolean parameter controls the level of detail to show. Setting - * {@code true} will output the array in full. Setting {@code false} will output - * a summary, typically the size of the array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info - * @return this - */ - public ToStringBuilder append(final String fieldName, final double[] array, final boolean fullDetail) { - style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); - return this; - } - - /** - *

- * Append to the {@code toString} an {@code float} value. - *

- * - * @param fieldName the field name - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final float value) { - style.append(buffer, fieldName, value); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code float} array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final float[] array) { - style.append(buffer, fieldName, array, null); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code float} array. - *

- * - *

- * A boolean parameter controls the level of detail to show. Setting - * {@code true} will output the array in full. Setting {@code false} will output - * a summary, typically the size of the array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info - * @return this - */ - public ToStringBuilder append(final String fieldName, final float[] array, final boolean fullDetail) { - style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); - return this; - } - - /** - *

- * Append to the {@code toString} an {@code int} value. - *

- * - * @param fieldName the field name - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final int value) { - style.append(buffer, fieldName, value); - return this; - } - - /** - *

- * Append to the {@code toString} an {@code int} array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final int[] array) { - style.append(buffer, fieldName, array, null); - return this; - } - - /** - *

- * Append to the {@code toString} an {@code int} array. - *

- * - *

- * A boolean parameter controls the level of detail to show. Setting - * {@code true} will output the array in full. Setting {@code false} will output - * a summary, typically the size of the array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info - * @return this - */ - public ToStringBuilder append(final String fieldName, final int[] array, final boolean fullDetail) { - style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code long} value. - *

- * - * @param fieldName the field name - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final long value) { - style.append(buffer, fieldName, value); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code long} array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final long[] array) { - style.append(buffer, fieldName, array, null); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code long} array. - *

- * - *

- * A boolean parameter controls the level of detail to show. Setting - * {@code true} will output the array in full. Setting {@code false} will output - * a summary, typically the size of the array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info - * @return this - */ - public ToStringBuilder append(final String fieldName, final long[] array, final boolean fullDetail) { - style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); - return this; - } - - /** - *

- * Append to the {@code toString} an {@code Object} value. - *

- * - * @param fieldName the field name - * @param obj the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final Object obj) { - style.append(buffer, fieldName, obj, null); - return this; - } - - /** - *

- * Append to the {@code toString} an {@code Object} value. - *

- * - * @param fieldName the field name - * @param obj the value to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info - * @return this - */ - public ToStringBuilder append(final String fieldName, final Object obj, final boolean fullDetail) { - style.append(buffer, fieldName, obj, Boolean.valueOf(fullDetail)); - return this; - } - - /** - *

- * Append to the {@code toString} an {@code Object} array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final Object[] array) { - style.append(buffer, fieldName, array, null); - return this; - } - - /** - *

- * Append to the {@code toString} an {@code Object} array. - *

- * - *

- * A boolean parameter controls the level of detail to show. Setting - * {@code true} will output the array in full. Setting {@code false} will output - * a summary, typically the size of the array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info - * @return this - */ - public ToStringBuilder append(final String fieldName, final Object[] array, final boolean fullDetail) { - style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); - return this; - } - - /** - *

- * Append to the {@code toString} an {@code short} value. - *

- * - * @param fieldName the field name - * @param value the value to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final short value) { - style.append(buffer, fieldName, value); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code short} array. - *

- * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @return this - */ - public ToStringBuilder append(final String fieldName, final short[] array) { - style.append(buffer, fieldName, array, null); - return this; - } - - /** - *

- * Append to the {@code toString} a {@code short} array. - *

- * - *

- * A boolean parameter controls the level of detail to show. Setting - * {@code true} will output the array in full. Setting {@code false} will output - * a summary, typically the size of the array. - * - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info - * @return this - */ - public ToStringBuilder append(final String fieldName, final short[] array, final boolean fullDetail) { - style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); - return this; - } - - /** - *

- * Appends with the same format as the default Object toString() - * method. Appends the class name followed by - * {@link System#identityHashCode(java.lang.Object)}. - *

- * - * @param srcObject the {@code Object} whose class name and id to output - * @return this - * @since 2.0 - */ - public ToStringBuilder appendAsObjectToString(final Object srcObject) { - ObjectUtils.identityToString(this.getStringBuffer(), srcObject); - return this; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append the {@code toString} from the superclass. - *

- * - *

- * This method assumes that the superclass uses the same {@code ToStringStyle} - * as this one. - *

- * - *

- * If {@code superToString} is {@code null}, no change is made. - *

- * - * @param superToString the result of {@code super.toString()} - * @return this - * @since 2.0 - */ - public ToStringBuilder appendSuper(final String superToString) { - if (superToString != null) { - style.appendSuper(buffer, superToString); - } - return this; - } - - /** - *

- * Append the {@code toString} from another object. - *

- * - *

- * This method is useful where a class delegates most of the implementation of - * its properties to another class. You can then call {@code toString()} on the - * other class and pass the result into this method. - *

- * - *
-	 * private AnotherObject delegate;
-	 * private String fieldInThisClass;
-	 *
-	 * public String toString() {
-	 * 	return new ToStringBuilder(this).appendToString(delegate.toString()).append(fieldInThisClass).toString();
-	 * }
-	 * 
- * - *

- * This method assumes that the other object uses the same {@code ToStringStyle} - * as this one. - *

- * - *

- * If the {@code toString} is {@code null}, no change is made. - *

- * - * @param toString the result of {@code toString()} on another object - * @return this - * @since 2.0 - */ - public ToStringBuilder appendToString(final String toString) { - if (toString != null) { - style.appendToString(buffer, toString); - } - return this; - } - - /** - *

- * Returns the {@code Object} being output. - *

- * - * @return The object being output. - * @since 2.0 - */ - public Object getObject() { - return object; - } - - /** - *

- * Gets the {@code StringBuffer} being populated. - *

- * - * @return the {@code StringBuffer} being populated - */ - public StringBuffer getStringBuffer() { - return buffer; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Gets the {@code ToStringStyle} being used. - *

- * - * @return the {@code ToStringStyle} being used - * @since 2.0 - */ - public ToStringStyle getStyle() { - return style; - } - - /** - *

- * Returns the built {@code toString}. - *

- * - *

- * This method appends the end of data indicator, and can only be called once. - * Use {@link #getStringBuffer} to get the current string state. - *

- * - *

- * If the object is {@code null}, return the style's {@code nullText} - *

- * - * @return the String {@code toString} - */ - @Override - public String toString() { - if (this.getObject() == null) { - this.getStringBuffer().append(this.getStyle().getNullText()); - } else { - style.appendEnd(this.getStringBuffer(), this.getObject()); - } - return this.getStringBuffer().toString(); - } - - /** - * Returns the String that was build as an object representation. The default - * implementation utilizes the {@link #toString()} implementation. - * - * @return the String {@code toString} - * - * @see #toString() - * - * @since 3.0 - */ - @Override - public String build() { - return toString(); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/builder/ToStringExclude.java b/sources/main/java/org/apache/commons/lang3/builder/ToStringExclude.java deleted file mode 100644 index be9c2c2d..00000000 --- a/sources/main/java/org/apache/commons/lang3/builder/ToStringExclude.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.builder; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Use this annotation to exclude a field from being used by the - * {@link ReflectionToStringBuilder}. - * - * @since 3.5 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ToStringExclude { - // empty -} diff --git a/sources/main/java/org/apache/commons/lang3/builder/ToStringStyle.java b/sources/main/java/org/apache/commons/lang3/builder/ToStringStyle.java deleted file mode 100644 index 1c88f7fb..00000000 --- a/sources/main/java/org/apache/commons/lang3/builder/ToStringStyle.java +++ /dev/null @@ -1,2910 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.builder; - -import java.io.Serializable; -import java.lang.reflect.Array; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; - -import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; - -/** - *

- * Controls {@code String} formatting for {@link ToStringBuilder}. The main - * public interface is always via {@code ToStringBuilder}. - *

- * - *

- * These classes are intended to be used as {@code Singletons}. There is no need - * to instantiate a new style each time. A program will generally use one of the - * predefined constants on this class. Alternatively, the - * {@link StandardToStringStyle} class can be used to set the individual - * settings. Thus most styles can be achieved without subclassing. - *

- * - *

- * If required, a subclass can override as many or as few of the methods as it - * requires. Each object type (from {@code boolean} to {@code long} to - * {@code Object} to {@code int[]}) has its own methods to output it. Most have - * two versions, detail and summary. - * - *

- * For example, the detail version of the array based methods will output the - * whole array, whereas the summary method will just output the array length. - *

- * - *

- * If you want to format the output of certain objects, such as dates, you must - * create a subclass and override a method. - *

- * - *
- * public class MyStyle extends ToStringStyle {
- * 	protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
- * 		if (value instanceof Date) {
- * 			value = new SimpleDateFormat("yyyy-MM-dd").format(value);
- * 		}
- * 		buffer.append(value);
- * 	}
- * }
- * 
- * - * @since 1.0 - */ -@SuppressWarnings("deprecation") // StringEscapeUtils -public abstract class ToStringStyle implements Serializable { - - /** - * Serialization version ID. - */ - private static final long serialVersionUID = -2587890625525655916L; - - /** - * The default toString style. Using the {@code Person} example from - * {@link ToStringBuilder}, the output would look like this: - * - *
-	 * Person@182f0db[name=John Doe,age=33,smoker=false]
-	 * 
- */ - public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle(); - - /** - * The multi line toString style. Using the {@code Person} example from - * {@link ToStringBuilder}, the output would look like this: - * - *
-	 * Person@182f0db[
-	 *   name=John Doe
-	 *   age=33
-	 *   smoker=false
-	 * ]
-	 * 
- */ - public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle(); - - /** - * The no field names toString style. Using the {@code Person} example from - * {@link ToStringBuilder}, the output would look like this: - * - *
-	 * Person@182f0db[John Doe,33,false]
-	 * 
- */ - public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle(); - - /** - * The short prefix toString style. Using the {@code Person} example from - * {@link ToStringBuilder}, the output would look like this: - * - *
-	 * Person[name=John Doe,age=33,smoker=false]
-	 * 
- * - * @since 2.1 - */ - public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle(); - - /** - * The simple toString style. Using the {@code Person} example from - * {@link ToStringBuilder}, the output would look like this: - * - *
-	 * John Doe,33,false
-	 * 
- */ - public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle(); - - /** - * The no class name toString style. Using the {@code Person} example from - * {@link ToStringBuilder}, the output would look like this: - * - *
-	 * [name=John Doe,age=33,smoker=false]
-	 * 
- * - * @since 3.4 - */ - public static final ToStringStyle NO_CLASS_NAME_STYLE = new NoClassNameToStringStyle(); - - /** - * The JSON toString style. Using the {@code Person} example from - * {@link ToStringBuilder}, the output would look like this: - * - *
-	 * {"name": "John Doe", "age": 33, "smoker": true}
-	 * 
- * - * Note: Since field names are mandatory in JSON, this - * ToStringStyle will throw an {@link UnsupportedOperationException} if no field - * name is passed in while appending. Furthermore This ToStringStyle will only - * generate valid JSON if referenced objects also produce JSON when calling - * {@code toString()} on them. - * - * @since 3.4 - * @see json.org - */ - public static final ToStringStyle JSON_STYLE = new JsonToStringStyle(); - - /** - *

- * A registry of objects used by {@code reflectionToString} methods to detect - * cyclical object references and avoid infinite loops. - *

- */ - private static final ThreadLocal> REGISTRY = new ThreadLocal<>(); - /* - * Note that objects of this class are generally shared between threads, so an - * instance variable would not be suitable here. - * - * In normal use the registry should always be left empty, because the caller - * should call toString() which will clean up. - * - * See LANG-792 - */ - - /** - *

- * Returns the registry of objects being traversed by the - * {@code reflectionToString} methods in the current thread. - *

- * - * @return Set the registry of objects being traversed - */ - static Map getRegistry() { - return REGISTRY.get(); - } - - /** - *

- * Returns {@code true} if the registry contains the given object. Used by the - * reflection methods to avoid infinite loops. - *

- * - * @param value The object to lookup in the registry. - * @return boolean {@code true} if the registry contains the given object. - */ - static boolean isRegistered(final Object value) { - final Map m = getRegistry(); - return m != null && m.containsKey(value); - } - - /** - *

- * Registers the given object. Used by the reflection methods to avoid infinite - * loops. - *

- * - * @param value The object to register. - */ - static void register(final Object value) { - if (value != null) { - final Map m = getRegistry(); - if (m == null) { - REGISTRY.set(new HashMap<>()); - } - getRegistry().put(value, null); - } - } - - /** - *

- * Unregisters the given object. - *

- * - *

- * Used by the reflection methods to avoid infinite loops. - *

- * - * @param value The object to unregister. - */ - static void unregister(final Object value) { - if (value != null) { - final Map m = getRegistry(); - if (m != null) { - m.remove(value); - if (m.isEmpty()) { - REGISTRY.remove(); - } - } - } - } - - /** - * Whether to use the field names, the default is {@code true}. - */ - private boolean useFieldNames = true; - - /** - * Whether to use the class name, the default is {@code true}. - */ - private boolean useClassName = true; - - /** - * Whether to use short class names, the default is {@code false}. - */ - private boolean useShortClassName; - - /** - * Whether to use the identity hash code, the default is {@code true}. - */ - private boolean useIdentityHashCode = true; - - /** - * The content start {@code '['}. - */ - private String contentStart = "["; - - /** - * The content end {@code ']'}. - */ - private String contentEnd = "]"; - - /** - * The field name value separator {@code '='}. - */ - private String fieldNameValueSeparator = "="; - - /** - * Whether the field separator should be added before any other fields. - */ - private boolean fieldSeparatorAtStart; - - /** - * Whether the field separator should be added after any other fields. - */ - private boolean fieldSeparatorAtEnd; - - /** - * The field separator {@code ','}. - */ - private String fieldSeparator = ","; - - /** - * The array start '{'. - */ - private String arrayStart = "{"; - - /** - * The array separator {@code ','}. - */ - private String arraySeparator = ","; - - /** - * The detail for array content. - */ - private boolean arrayContentDetail = true; - - /** - * The array end {@code '}'}. - */ - private String arrayEnd = "}"; - - /** - * The value to use when fullDetail is {@code null}, the default value is - * {@code true}. - */ - private boolean defaultFullDetail = true; - - /** - * The {@code null} text {@code '<null>'}. - */ - private String nullText = ""; - - /** - * The summary size text start {@code '<size'}. - */ - private String sizeStartText = " - * Constructor. - *

- */ - protected ToStringStyle() { - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} the superclass toString. - *

- *

- * NOTE: It assumes that the toString has been created from the same - * ToStringStyle. - *

- * - *

- * A {@code null} {@code superToString} is ignored. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param superToString the {@code super.toString()} - * @since 2.0 - */ - public void appendSuper(final StringBuffer buffer, final String superToString) { - appendToString(buffer, superToString); - } - - /** - *

- * Append to the {@code toString} another toString. - *

- *

- * NOTE: It assumes that the toString has been created from the same - * ToStringStyle. - *

- * - *

- * A {@code null} {@code toString} is ignored. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param toString the additional {@code toString} - * @since 2.0 - */ - public void appendToString(final StringBuffer buffer, final String toString) { - if (toString != null) { - final int pos1 = toString.indexOf(contentStart) + contentStart.length(); - final int pos2 = toString.lastIndexOf(contentEnd); - if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) { - if (fieldSeparatorAtStart) { - removeLastFieldSeparator(buffer); - } - buffer.append(toString, pos1, pos2); - appendFieldSeparator(buffer); - } - } - } - - /** - *

- * Append to the {@code toString} the start of data indicator. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param object the {@code Object} to build a {@code toString} for - */ - public void appendStart(final StringBuffer buffer, final Object object) { - if (object != null) { - appendClassName(buffer, object); - appendIdentityHashCode(buffer, object); - appendContentStart(buffer); - if (fieldSeparatorAtStart) { - appendFieldSeparator(buffer); - } - } - } - - /** - *

- * Append to the {@code toString} the end of data indicator. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param object the {@code Object} to build a {@code toString} for. - */ - public void appendEnd(final StringBuffer buffer, final Object object) { - if (!this.fieldSeparatorAtEnd) { - removeLastFieldSeparator(buffer); - } - appendContentEnd(buffer); - unregister(object); - } - - /** - *

- * Remove the last field separator from the buffer. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @since 2.0 - */ - protected void removeLastFieldSeparator(final StringBuffer buffer) { - if (StringUtils.endsWith(buffer, fieldSeparator)) { - buffer.setLength(buffer.length() - fieldSeparator.length()); - } - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} an {@code Object} value, printing the full - * {@code toString} of the {@code Object} passed in. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param value the value to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info, - * {@code null} for style decides - */ - public void append(final StringBuffer buffer, final String fieldName, final Object value, - final Boolean fullDetail) { - appendFieldStart(buffer, fieldName); - - if (value == null) { - appendNullText(buffer, fieldName); - - } else { - appendInternal(buffer, fieldName, value, isFullDetail(fullDetail)); - } - - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} an {@code Object}, correctly interpreting its - * type. - *

- * - *

- * This method performs the main lookup by Class type to correctly route arrays, - * {@code Collections}, {@code Maps} and {@code Objects} to the appropriate - * method. - *

- * - *

- * Either detail or summary views can be specified. - *

- * - *

- * If a cycle is detected, an object will be appended with the - * {@code Object.toString()} format. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString}, not {@code null} - * @param detail output detail or not - */ - protected void appendInternal(final StringBuffer buffer, final String fieldName, final Object value, - final boolean detail) { - if (isRegistered(value) - && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) { - appendCyclicObject(buffer, fieldName, value); - return; - } - - register(value); - - try { - if (value instanceof Collection) { - if (detail) { - appendDetail(buffer, fieldName, (Collection) value); - } else { - appendSummarySize(buffer, fieldName, ((Collection) value).size()); - } - - } else if (value instanceof Map) { - if (detail) { - appendDetail(buffer, fieldName, (Map) value); - } else { - appendSummarySize(buffer, fieldName, ((Map) value).size()); - } - - } else if (value instanceof long[]) { - if (detail) { - appendDetail(buffer, fieldName, (long[]) value); - } else { - appendSummary(buffer, fieldName, (long[]) value); - } - - } else if (value instanceof int[]) { - if (detail) { - appendDetail(buffer, fieldName, (int[]) value); - } else { - appendSummary(buffer, fieldName, (int[]) value); - } - - } else if (value instanceof short[]) { - if (detail) { - appendDetail(buffer, fieldName, (short[]) value); - } else { - appendSummary(buffer, fieldName, (short[]) value); - } - - } else if (value instanceof byte[]) { - if (detail) { - appendDetail(buffer, fieldName, (byte[]) value); - } else { - appendSummary(buffer, fieldName, (byte[]) value); - } - - } else if (value instanceof char[]) { - if (detail) { - appendDetail(buffer, fieldName, (char[]) value); - } else { - appendSummary(buffer, fieldName, (char[]) value); - } - - } else if (value instanceof double[]) { - if (detail) { - appendDetail(buffer, fieldName, (double[]) value); - } else { - appendSummary(buffer, fieldName, (double[]) value); - } - - } else if (value instanceof float[]) { - if (detail) { - appendDetail(buffer, fieldName, (float[]) value); - } else { - appendSummary(buffer, fieldName, (float[]) value); - } - - } else if (value instanceof boolean[]) { - if (detail) { - appendDetail(buffer, fieldName, (boolean[]) value); - } else { - appendSummary(buffer, fieldName, (boolean[]) value); - } - - } else if (value.getClass().isArray()) { - if (detail) { - appendDetail(buffer, fieldName, (Object[]) value); - } else { - appendSummary(buffer, fieldName, (Object[]) value); - } - - } else if (detail) { - appendDetail(buffer, fieldName, value); - } else { - appendSummary(buffer, fieldName, value); - } - } finally { - unregister(value); - } - } - - /** - *

- * Append to the {@code toString} an {@code Object} value that has been detected - * to participate in a cycle. This implementation will print the standard string - * value of the value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString}, not {@code null} - * - * @since 2.2 - */ - protected void appendCyclicObject(final StringBuffer buffer, final String fieldName, final Object value) { - ObjectUtils.identityToString(buffer, value); - } - - /** - *

- * Append to the {@code toString} an {@code Object} value, printing the full - * detail of the {@code Object}. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString}, not {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { - buffer.append(value); - } - - /** - *

- * Append to the {@code toString} a {@code Collection}. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param coll the {@code Collection} to add to the {@code toString}, not - * {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection coll) { - buffer.append(coll); - } - - /** - *

- * Append to the {@code toString} a {@code Map}. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param map the {@code Map} to add to the {@code toString}, not - * {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final Map map) { - buffer.append(map); - } - - /** - *

- * Append to the {@code toString} an {@code Object} value, printing a summary of - * the {@code Object}. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString}, not {@code null} - */ - protected void appendSummary(final StringBuffer buffer, final String fieldName, final Object value) { - buffer.append(summaryObjectStartText); - buffer.append(getShortClassName(value.getClass())); - buffer.append(summaryObjectEndText); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code long} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param value the value to add to the {@code toString} - */ - public void append(final StringBuffer buffer, final String fieldName, final long value) { - appendFieldStart(buffer, fieldName); - appendDetail(buffer, fieldName, value); - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} a {@code long} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final long value) { - buffer.append(value); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} an {@code int} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param value the value to add to the {@code toString} - */ - public void append(final StringBuffer buffer, final String fieldName, final int value) { - appendFieldStart(buffer, fieldName); - appendDetail(buffer, fieldName, value); - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} an {@code int} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final int value) { - buffer.append(value); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code short} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param value the value to add to the {@code toString} - */ - public void append(final StringBuffer buffer, final String fieldName, final short value) { - appendFieldStart(buffer, fieldName); - appendDetail(buffer, fieldName, value); - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} a {@code short} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final short value) { - buffer.append(value); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code byte} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param value the value to add to the {@code toString} - */ - public void append(final StringBuffer buffer, final String fieldName, final byte value) { - appendFieldStart(buffer, fieldName); - appendDetail(buffer, fieldName, value); - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} a {@code byte} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte value) { - buffer.append(value); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code char} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param value the value to add to the {@code toString} - */ - public void append(final StringBuffer buffer, final String fieldName, final char value) { - appendFieldStart(buffer, fieldName); - appendDetail(buffer, fieldName, value); - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} a {@code char} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final char value) { - buffer.append(value); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code double} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param value the value to add to the {@code toString} - */ - public void append(final StringBuffer buffer, final String fieldName, final double value) { - appendFieldStart(buffer, fieldName); - appendDetail(buffer, fieldName, value); - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} a {@code double} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final double value) { - buffer.append(value); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code float} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param value the value to add to the {@code toString} - */ - public void append(final StringBuffer buffer, final String fieldName, final float value) { - appendFieldStart(buffer, fieldName); - appendDetail(buffer, fieldName, value); - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} a {@code float} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final float value) { - buffer.append(value); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code boolean} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param value the value to add to the {@code toString} - */ - public void append(final StringBuffer buffer, final String fieldName, final boolean value) { - appendFieldStart(buffer, fieldName); - appendDetail(buffer, fieldName, value); - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} a {@code boolean} value. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param value the value to add to the {@code toString} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean value) { - buffer.append(value); - } - - /** - *

- * Append to the {@code toString} an {@code Object} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param array the array to add to the toString - * @param fullDetail {@code true} for detail, {@code false} for summary info, - * {@code null} for style decides - */ - public void append(final StringBuffer buffer, final String fieldName, final Object[] array, - final Boolean fullDetail) { - appendFieldStart(buffer, fieldName); - - if (array == null) { - appendNullText(buffer, fieldName); - - } else if (isFullDetail(fullDetail)) { - appendDetail(buffer, fieldName, array); - - } else { - appendSummary(buffer, fieldName, array); - } - - appendFieldEnd(buffer, fieldName); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} the detail of an {@code Object} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) { - buffer.append(arrayStart); - for (int i = 0; i < array.length; i++) { - final Object item = array[i]; - appendDetail(buffer, fieldName, i, item); - } - buffer.append(arrayEnd); - } - - /** - *

- * Append to the {@code toString} the detail of an {@code Object} array item. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param i the array item index to add - * @param item the array item to add - * @since 3.11 - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final int i, final Object item) { - if (i > 0) { - buffer.append(arraySeparator); - } - if (item == null) { - appendNullText(buffer, fieldName); - } else { - appendInternal(buffer, fieldName, item, arrayContentDetail); - } - } - - /** - *

- * Append to the {@code toString} the detail of an array type. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - * @since 2.0 - */ - protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) { - buffer.append(arrayStart); - final int length = Array.getLength(array); - for (int i = 0; i < length; i++) { - final Object item = Array.get(array, i); - appendDetail(buffer, fieldName, i, item); - } - buffer.append(arrayEnd); - } - - /** - *

- * Append to the {@code toString} a summary of an {@code Object} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendSummary(final StringBuffer buffer, final String fieldName, final Object[] array) { - appendSummarySize(buffer, fieldName, array.length); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code long} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info, - * {@code null} for style decides - */ - public void append(final StringBuffer buffer, final String fieldName, final long[] array, - final Boolean fullDetail) { - appendFieldStart(buffer, fieldName); - - if (array == null) { - appendNullText(buffer, fieldName); - - } else if (isFullDetail(fullDetail)) { - appendDetail(buffer, fieldName, array); - - } else { - appendSummary(buffer, fieldName, array); - } - - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} the detail of a {@code long} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) { - buffer.append(arrayStart); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - buffer.append(arraySeparator); - } - appendDetail(buffer, fieldName, array[i]); - } - buffer.append(arrayEnd); - } - - /** - *

- * Append to the {@code toString} a summary of a {@code long} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendSummary(final StringBuffer buffer, final String fieldName, final long[] array) { - appendSummarySize(buffer, fieldName, array.length); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} an {@code int} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info, - * {@code null} for style decides - */ - public void append(final StringBuffer buffer, final String fieldName, final int[] array, final Boolean fullDetail) { - appendFieldStart(buffer, fieldName); - - if (array == null) { - appendNullText(buffer, fieldName); - - } else if (isFullDetail(fullDetail)) { - appendDetail(buffer, fieldName, array); - - } else { - appendSummary(buffer, fieldName, array); - } - - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} the detail of an {@code int} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) { - buffer.append(arrayStart); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - buffer.append(arraySeparator); - } - appendDetail(buffer, fieldName, array[i]); - } - buffer.append(arrayEnd); - } - - /** - *

- * Append to the {@code toString} a summary of an {@code int} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendSummary(final StringBuffer buffer, final String fieldName, final int[] array) { - appendSummarySize(buffer, fieldName, array.length); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code short} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info, - * {@code null} for style decides - */ - public void append(final StringBuffer buffer, final String fieldName, final short[] array, - final Boolean fullDetail) { - appendFieldStart(buffer, fieldName); - - if (array == null) { - appendNullText(buffer, fieldName); - - } else if (isFullDetail(fullDetail)) { - appendDetail(buffer, fieldName, array); - - } else { - appendSummary(buffer, fieldName, array); - } - - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} the detail of a {@code short} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) { - buffer.append(arrayStart); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - buffer.append(arraySeparator); - } - appendDetail(buffer, fieldName, array[i]); - } - buffer.append(arrayEnd); - } - - /** - *

- * Append to the {@code toString} a summary of a {@code short} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendSummary(final StringBuffer buffer, final String fieldName, final short[] array) { - appendSummarySize(buffer, fieldName, array.length); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code byte} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info, - * {@code null} for style decides - */ - public void append(final StringBuffer buffer, final String fieldName, final byte[] array, - final Boolean fullDetail) { - appendFieldStart(buffer, fieldName); - - if (array == null) { - appendNullText(buffer, fieldName); - - } else if (isFullDetail(fullDetail)) { - appendDetail(buffer, fieldName, array); - - } else { - appendSummary(buffer, fieldName, array); - } - - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} the detail of a {@code byte} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte[] array) { - buffer.append(arrayStart); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - buffer.append(arraySeparator); - } - appendDetail(buffer, fieldName, array[i]); - } - buffer.append(arrayEnd); - } - - /** - *

- * Append to the {@code toString} a summary of a {@code byte} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendSummary(final StringBuffer buffer, final String fieldName, final byte[] array) { - appendSummarySize(buffer, fieldName, array.length); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code char} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param array the array to add to the {@code toString} - * @param fullDetail {@code true} for detail, {@code false} for summary info, - * {@code null} for style decides - */ - public void append(final StringBuffer buffer, final String fieldName, final char[] array, - final Boolean fullDetail) { - appendFieldStart(buffer, fieldName); - - if (array == null) { - appendNullText(buffer, fieldName); - - } else if (isFullDetail(fullDetail)) { - appendDetail(buffer, fieldName, array); - - } else { - appendSummary(buffer, fieldName, array); - } - - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} the detail of a {@code char} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final char[] array) { - buffer.append(arrayStart); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - buffer.append(arraySeparator); - } - appendDetail(buffer, fieldName, array[i]); - } - buffer.append(arrayEnd); - } - - /** - *

- * Append to the {@code toString} a summary of a {@code char} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendSummary(final StringBuffer buffer, final String fieldName, final char[] array) { - appendSummarySize(buffer, fieldName, array.length); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code double} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param array the array to add to the toString - * @param fullDetail {@code true} for detail, {@code false} for summary info, - * {@code null} for style decides - */ - public void append(final StringBuffer buffer, final String fieldName, final double[] array, - final Boolean fullDetail) { - appendFieldStart(buffer, fieldName); - - if (array == null) { - appendNullText(buffer, fieldName); - - } else if (isFullDetail(fullDetail)) { - appendDetail(buffer, fieldName, array); - - } else { - appendSummary(buffer, fieldName, array); - } - - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} the detail of a {@code double} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final double[] array) { - buffer.append(arrayStart); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - buffer.append(arraySeparator); - } - appendDetail(buffer, fieldName, array[i]); - } - buffer.append(arrayEnd); - } - - /** - *

- * Append to the {@code toString} a summary of a {@code double} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendSummary(final StringBuffer buffer, final String fieldName, final double[] array) { - appendSummarySize(buffer, fieldName, array.length); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code float} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param array the array to add to the toString - * @param fullDetail {@code true} for detail, {@code false} for summary info, - * {@code null} for style decides - */ - public void append(final StringBuffer buffer, final String fieldName, final float[] array, - final Boolean fullDetail) { - appendFieldStart(buffer, fieldName); - - if (array == null) { - appendNullText(buffer, fieldName); - - } else if (isFullDetail(fullDetail)) { - appendDetail(buffer, fieldName, array); - - } else { - appendSummary(buffer, fieldName, array); - } - - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} the detail of a {@code float} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final float[] array) { - buffer.append(arrayStart); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - buffer.append(arraySeparator); - } - appendDetail(buffer, fieldName, array[i]); - } - buffer.append(arrayEnd); - } - - /** - *

- * Append to the {@code toString} a summary of a {@code float} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendSummary(final StringBuffer buffer, final String fieldName, final float[] array) { - appendSummarySize(buffer, fieldName, array.length); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} a {@code boolean} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - * @param array the array to add to the toString - * @param fullDetail {@code true} for detail, {@code false} for summary info, - * {@code null} for style decides - */ - public void append(final StringBuffer buffer, final String fieldName, final boolean[] array, - final Boolean fullDetail) { - appendFieldStart(buffer, fieldName); - - if (array == null) { - appendNullText(buffer, fieldName); - - } else if (isFullDetail(fullDetail)) { - appendDetail(buffer, fieldName, array); - - } else { - appendSummary(buffer, fieldName, array); - } - - appendFieldEnd(buffer, fieldName); - } - - /** - *

- * Append to the {@code toString} the detail of a {@code boolean} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) { - buffer.append(arrayStart); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - buffer.append(arraySeparator); - } - appendDetail(buffer, fieldName, array[i]); - } - buffer.append(arrayEnd); - } - - /** - *

- * Append to the {@code toString} a summary of a {@code boolean} array. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param array the array to add to the {@code toString}, not {@code null} - */ - protected void appendSummary(final StringBuffer buffer, final String fieldName, final boolean[] array) { - appendSummarySize(buffer, fieldName, array.length); - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Append to the {@code toString} the class name. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param object the {@code Object} whose name to output - */ - protected void appendClassName(final StringBuffer buffer, final Object object) { - if (useClassName && object != null) { - register(object); - if (useShortClassName) { - buffer.append(getShortClassName(object.getClass())); - } else { - buffer.append(object.getClass().getName()); - } - } - } - - /** - *

- * Append the {@link System#identityHashCode(java.lang.Object)}. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param object the {@code Object} whose id to output - */ - protected void appendIdentityHashCode(final StringBuffer buffer, final Object object) { - if (this.isUseIdentityHashCode() && object != null) { - register(object); - buffer.append('@'); - buffer.append(Integer.toHexString(System.identityHashCode(object))); - } - } - - /** - *

- * Append to the {@code toString} the content start. - *

- * - * @param buffer the {@code StringBuffer} to populate - */ - protected void appendContentStart(final StringBuffer buffer) { - buffer.append(contentStart); - } - - /** - *

- * Append to the {@code toString} the content end. - *

- * - * @param buffer the {@code StringBuffer} to populate - */ - protected void appendContentEnd(final StringBuffer buffer) { - buffer.append(contentEnd); - } - - /** - *

- * Append to the {@code toString} an indicator for {@code null}. - *

- * - *

- * The default indicator is {@code '<null>'}. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - */ - protected void appendNullText(final StringBuffer buffer, final String fieldName) { - buffer.append(nullText); - } - - /** - *

- * Append to the {@code toString} the field separator. - *

- * - * @param buffer the {@code StringBuffer} to populate - */ - protected void appendFieldSeparator(final StringBuffer buffer) { - buffer.append(fieldSeparator); - } - - /** - *

- * Append to the {@code toString} the field start. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name - */ - protected void appendFieldStart(final StringBuffer buffer, final String fieldName) { - if (useFieldNames && fieldName != null) { - buffer.append(fieldName); - buffer.append(fieldNameValueSeparator); - } - } - - /** - *

- * Append to the {@code toString} the field end. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - */ - protected void appendFieldEnd(final StringBuffer buffer, final String fieldName) { - appendFieldSeparator(buffer); - } - - /** - *

- * Append to the {@code toString} a size summary. - *

- * - *

- * The size summary is used to summarize the contents of {@code Collections}, - * {@code Maps} and arrays. - *

- * - *

- * The output consists of a prefix, the passed in size and a suffix. - *

- * - *

- * The default format is {@code '<size=n>'}. - *

- * - * @param buffer the {@code StringBuffer} to populate - * @param fieldName the field name, typically not used as already appended - * @param size the size to append - */ - protected void appendSummarySize(final StringBuffer buffer, final String fieldName, final int size) { - buffer.append(sizeStartText); - buffer.append(size); - buffer.append(sizeEndText); - } - - /** - *

- * Is this field to be output in full detail. - *

- * - *

- * This method converts a detail request into a detail level. The calling code - * may request full detail ({@code true}), but a subclass might ignore that and - * always return {@code false}. The calling code may pass in {@code null} - * indicating that it doesn't care about the detail level. In this case the - * default detail level is used. - *

- * - * @param fullDetailRequest the detail level requested - * @return whether full detail is to be shown - */ - protected boolean isFullDetail(final Boolean fullDetailRequest) { - if (fullDetailRequest == null) { - return defaultFullDetail; - } - return fullDetailRequest.booleanValue(); - } - - /** - *

- * Gets the short class name for a class. - *

- * - *

- * The short class name is the classname excluding the package name. - *

- * - * @param cls the {@code Class} to get the short name of - * @return the short name - */ - protected String getShortClassName(final Class cls) { - return cls.getSimpleName(); - } - - // Setters and getters for the customizable parts of the style - // These methods are not expected to be overridden, except to make public - // (They are not public so that immutable subclasses can be written) - // --------------------------------------------------------------------- - - /** - *

- * Gets whether to use the class name. - *

- * - * @return the current useClassName flag - */ - protected boolean isUseClassName() { - return useClassName; - } - - /** - *

- * Sets whether to use the class name. - *

- * - * @param useClassName the new useClassName flag - */ - protected void setUseClassName(final boolean useClassName) { - this.useClassName = useClassName; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets whether to output short or long class names. - *

- * - * @return the current useShortClassName flag - * @since 2.0 - */ - protected boolean isUseShortClassName() { - return useShortClassName; - } - - /** - *

- * Sets whether to output short or long class names. - *

- * - * @param useShortClassName the new useShortClassName flag - * @since 2.0 - */ - protected void setUseShortClassName(final boolean useShortClassName) { - this.useShortClassName = useShortClassName; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets whether to use the identity hash code. - *

- * - * @return the current useIdentityHashCode flag - */ - protected boolean isUseIdentityHashCode() { - return useIdentityHashCode; - } - - /** - *

- * Sets whether to use the identity hash code. - *

- * - * @param useIdentityHashCode the new useIdentityHashCode flag - */ - protected void setUseIdentityHashCode(final boolean useIdentityHashCode) { - this.useIdentityHashCode = useIdentityHashCode; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets whether to use the field names passed in. - *

- * - * @return the current useFieldNames flag - */ - protected boolean isUseFieldNames() { - return useFieldNames; - } - - /** - *

- * Sets whether to use the field names passed in. - *

- * - * @param useFieldNames the new useFieldNames flag - */ - protected void setUseFieldNames(final boolean useFieldNames) { - this.useFieldNames = useFieldNames; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets whether to use full detail when the caller doesn't specify. - *

- * - * @return the current defaultFullDetail flag - */ - protected boolean isDefaultFullDetail() { - return defaultFullDetail; - } - - /** - *

- * Sets whether to use full detail when the caller doesn't specify. - *

- * - * @param defaultFullDetail the new defaultFullDetail flag - */ - protected void setDefaultFullDetail(final boolean defaultFullDetail) { - this.defaultFullDetail = defaultFullDetail; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets whether to output array content detail. - *

- * - * @return the current array content detail setting - */ - protected boolean isArrayContentDetail() { - return arrayContentDetail; - } - - /** - *

- * Sets whether to output array content detail. - *

- * - * @param arrayContentDetail the new arrayContentDetail flag - */ - protected void setArrayContentDetail(final boolean arrayContentDetail) { - this.arrayContentDetail = arrayContentDetail; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the array start text. - *

- * - * @return the current array start text - */ - protected String getArrayStart() { - return arrayStart; - } - - /** - *

- * Sets the array start text. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param arrayStart the new array start text - */ - protected void setArrayStart(String arrayStart) { - if (arrayStart == null) { - arrayStart = StringUtils.EMPTY; - } - this.arrayStart = arrayStart; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the array end text. - *

- * - * @return the current array end text - */ - protected String getArrayEnd() { - return arrayEnd; - } - - /** - *

- * Sets the array end text. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param arrayEnd the new array end text - */ - protected void setArrayEnd(String arrayEnd) { - if (arrayEnd == null) { - arrayEnd = StringUtils.EMPTY; - } - this.arrayEnd = arrayEnd; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the array separator text. - *

- * - * @return the current array separator text - */ - protected String getArraySeparator() { - return arraySeparator; - } - - /** - *

- * Sets the array separator text. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param arraySeparator the new array separator text - */ - protected void setArraySeparator(String arraySeparator) { - if (arraySeparator == null) { - arraySeparator = StringUtils.EMPTY; - } - this.arraySeparator = arraySeparator; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the content start text. - *

- * - * @return the current content start text - */ - protected String getContentStart() { - return contentStart; - } - - /** - *

- * Sets the content start text. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param contentStart the new content start text - */ - protected void setContentStart(String contentStart) { - if (contentStart == null) { - contentStart = StringUtils.EMPTY; - } - this.contentStart = contentStart; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the content end text. - *

- * - * @return the current content end text - */ - protected String getContentEnd() { - return contentEnd; - } - - /** - *

- * Sets the content end text. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param contentEnd the new content end text - */ - protected void setContentEnd(String contentEnd) { - if (contentEnd == null) { - contentEnd = StringUtils.EMPTY; - } - this.contentEnd = contentEnd; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the field name value separator text. - *

- * - * @return the current field name value separator text - */ - protected String getFieldNameValueSeparator() { - return fieldNameValueSeparator; - } - - /** - *

- * Sets the field name value separator text. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param fieldNameValueSeparator the new field name value separator text - */ - protected void setFieldNameValueSeparator(String fieldNameValueSeparator) { - if (fieldNameValueSeparator == null) { - fieldNameValueSeparator = StringUtils.EMPTY; - } - this.fieldNameValueSeparator = fieldNameValueSeparator; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the field separator text. - *

- * - * @return the current field separator text - */ - protected String getFieldSeparator() { - return fieldSeparator; - } - - /** - *

- * Sets the field separator text. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param fieldSeparator the new field separator text - */ - protected void setFieldSeparator(String fieldSeparator) { - if (fieldSeparator == null) { - fieldSeparator = StringUtils.EMPTY; - } - this.fieldSeparator = fieldSeparator; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets whether the field separator should be added at the start of each buffer. - *

- * - * @return the fieldSeparatorAtStart flag - * @since 2.0 - */ - protected boolean isFieldSeparatorAtStart() { - return fieldSeparatorAtStart; - } - - /** - *

- * Sets whether the field separator should be added at the start of each buffer. - *

- * - * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag - * @since 2.0 - */ - protected void setFieldSeparatorAtStart(final boolean fieldSeparatorAtStart) { - this.fieldSeparatorAtStart = fieldSeparatorAtStart; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets whether the field separator should be added at the end of each buffer. - *

- * - * @return fieldSeparatorAtEnd flag - * @since 2.0 - */ - protected boolean isFieldSeparatorAtEnd() { - return fieldSeparatorAtEnd; - } - - /** - *

- * Sets whether the field separator should be added at the end of each buffer. - *

- * - * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag - * @since 2.0 - */ - protected void setFieldSeparatorAtEnd(final boolean fieldSeparatorAtEnd) { - this.fieldSeparatorAtEnd = fieldSeparatorAtEnd; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the text to output when {@code null} found. - *

- * - * @return the current text to output when null found - */ - protected String getNullText() { - return nullText; - } - - /** - *

- * Sets the text to output when {@code null} found. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param nullText the new text to output when null found - */ - protected void setNullText(String nullText) { - if (nullText == null) { - nullText = StringUtils.EMPTY; - } - this.nullText = nullText; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the start text to output when a {@code Collection}, {@code Map} or array - * size is output. - *

- * - *

- * This is output before the size value. - *

- * - * @return the current start of size text - */ - protected String getSizeStartText() { - return sizeStartText; - } - - /** - *

- * Sets the start text to output when a {@code Collection}, {@code Map} or array - * size is output. - *

- * - *

- * This is output before the size value. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param sizeStartText the new start of size text - */ - protected void setSizeStartText(String sizeStartText) { - if (sizeStartText == null) { - sizeStartText = StringUtils.EMPTY; - } - this.sizeStartText = sizeStartText; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the end text to output when a {@code Collection}, {@code Map} or array - * size is output. - *

- * - *

- * This is output after the size value. - *

- * - * @return the current end of size text - */ - protected String getSizeEndText() { - return sizeEndText; - } - - /** - *

- * Sets the end text to output when a {@code Collection}, {@code Map} or array - * size is output. - *

- * - *

- * This is output after the size value. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param sizeEndText the new end of size text - */ - protected void setSizeEndText(String sizeEndText) { - if (sizeEndText == null) { - sizeEndText = StringUtils.EMPTY; - } - this.sizeEndText = sizeEndText; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the start text to output when an {@code Object} is output in summary - * mode. - *

- * - *

- * This is output before the size value. - *

- * - * @return the current start of summary text - */ - protected String getSummaryObjectStartText() { - return summaryObjectStartText; - } - - /** - *

- * Sets the start text to output when an {@code Object} is output in summary - * mode. - *

- * - *

- * This is output before the size value. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param summaryObjectStartText the new start of summary text - */ - protected void setSummaryObjectStartText(String summaryObjectStartText) { - if (summaryObjectStartText == null) { - summaryObjectStartText = StringUtils.EMPTY; - } - this.summaryObjectStartText = summaryObjectStartText; - } - - // --------------------------------------------------------------------- - - /** - *

- * Gets the end text to output when an {@code Object} is output in summary mode. - *

- * - *

- * This is output after the size value. - *

- * - * @return the current end of summary text - */ - protected String getSummaryObjectEndText() { - return summaryObjectEndText; - } - - /** - *

- * Sets the end text to output when an {@code Object} is output in summary mode. - *

- * - *

- * This is output after the size value. - *

- * - *

- * {@code null} is accepted, but will be converted to an empty String. - *

- * - * @param summaryObjectEndText the new end of summary text - */ - protected void setSummaryObjectEndText(String summaryObjectEndText) { - if (summaryObjectEndText == null) { - summaryObjectEndText = StringUtils.EMPTY; - } - this.summaryObjectEndText = summaryObjectEndText; - } - - // ---------------------------------------------------------------------------- - - /** - *

- * Default {@code ToStringStyle}. - *

- * - *

- * This is an inner class rather than using {@code StandardToStringStyle} to - * ensure its immutability. - *

- */ - private static final class DefaultToStringStyle extends ToStringStyle { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 1L; - - /** - *

- * Constructor. - *

- * - *

- * Use the static constant rather than instantiating. - *

- */ - DefaultToStringStyle() { - } - - /** - *

- * Ensure {@code Singleton} after serialization. - *

- * - * @return the singleton - */ - private Object readResolve() { - return DEFAULT_STYLE; - } - - } - - // ---------------------------------------------------------------------------- - - /** - *

- * {@code ToStringStyle} that does not print out the field names. - *

- * - *

- * This is an inner class rather than using {@code StandardToStringStyle} to - * ensure its immutability. - */ - private static final class NoFieldNameToStringStyle extends ToStringStyle { - - private static final long serialVersionUID = 1L; - - /** - *

- * Constructor. - *

- * - *

- * Use the static constant rather than instantiating. - *

- */ - NoFieldNameToStringStyle() { - this.setUseFieldNames(false); - } - - /** - *

- * Ensure {@code Singleton} after serialization. - *

- * - * @return the singleton - */ - private Object readResolve() { - return NO_FIELD_NAMES_STYLE; - } - - } - - // ---------------------------------------------------------------------------- - - /** - *

- * {@code ToStringStyle} that prints out the short class name and no identity - * hashcode. - *

- * - *

- * This is an inner class rather than using {@code StandardToStringStyle} to - * ensure its immutability. - *

- */ - private static final class ShortPrefixToStringStyle extends ToStringStyle { - - private static final long serialVersionUID = 1L; - - /** - *

- * Constructor. - *

- * - *

- * Use the static constant rather than instantiating. - *

- */ - ShortPrefixToStringStyle() { - this.setUseShortClassName(true); - this.setUseIdentityHashCode(false); - } - - /** - *

- * Ensure Singleton after serialization. - *

- * - * @return the singleton - */ - private Object readResolve() { - return SHORT_PREFIX_STYLE; - } - - } - - // ---------------------------------------------------------------------------- - - /** - *

- * {@code ToStringStyle} that does not print out the classname, identity - * hashcode, content start or field name. - *

- * - *

- * This is an inner class rather than using {@code StandardToStringStyle} to - * ensure its immutability. - *

- */ - private static final class SimpleToStringStyle extends ToStringStyle { - - private static final long serialVersionUID = 1L; - - /** - *

- * Constructor. - *

- * - *

- * Use the static constant rather than instantiating. - *

- */ - SimpleToStringStyle() { - this.setUseClassName(false); - this.setUseIdentityHashCode(false); - this.setUseFieldNames(false); - this.setContentStart(StringUtils.EMPTY); - this.setContentEnd(StringUtils.EMPTY); - } - - /** - *

- * Ensure Singleton after serialization. - *

- * - * @return the singleton - */ - private Object readResolve() { - return SIMPLE_STYLE; - } - - } - - // ---------------------------------------------------------------------------- - - /** - *

- * {@code ToStringStyle} that outputs on multiple lines. - *

- * - *

- * This is an inner class rather than using {@code StandardToStringStyle} to - * ensure its immutability. - *

- */ - private static final class MultiLineToStringStyle extends ToStringStyle { - - private static final long serialVersionUID = 1L; - - /** - *

- * Constructor. - *

- * - *

- * Use the static constant rather than instantiating. - *

- */ - MultiLineToStringStyle() { - this.setContentStart("["); - this.setFieldSeparator(System.lineSeparator() + " "); - this.setFieldSeparatorAtStart(true); - this.setContentEnd(System.lineSeparator() + "]"); - } - - /** - *

- * Ensure {@code Singleton} after serialization. - *

- * - * @return the singleton - */ - private Object readResolve() { - return MULTI_LINE_STYLE; - } - - } - - // ---------------------------------------------------------------------------- - - /** - *

- * {@code ToStringStyle} that does not print out the classname and identity hash - * code but prints content start and field names. - *

- * - *

- * This is an inner class rather than using {@code StandardToStringStyle} to - * ensure its immutability. - *

- */ - private static final class NoClassNameToStringStyle extends ToStringStyle { - - private static final long serialVersionUID = 1L; - - /** - *

- * Constructor. - *

- * - *

- * Use the static constant rather than instantiating. - *

- */ - NoClassNameToStringStyle() { - this.setUseClassName(false); - this.setUseIdentityHashCode(false); - } - - /** - *

- * Ensure {@code Singleton} after serialization. - *

- * - * @return the singleton - */ - private Object readResolve() { - return NO_CLASS_NAME_STYLE; - } - - } - - // ---------------------------------------------------------------------------- - - /** - *

- * {@code ToStringStyle} that outputs with JSON format. - *

- * - *

- * This is an inner class rather than using {@code StandardToStringStyle} to - * ensure its immutability. - *

- * - * @since 3.4 - * @see json.org - */ - private static final class JsonToStringStyle extends ToStringStyle { - - private static final long serialVersionUID = 1L; - - private static final String FIELD_NAME_QUOTE = "\""; - - /** - *

- * Constructor. - *

- * - *

- * Use the static constant rather than instantiating. - *

- */ - JsonToStringStyle() { - this.setUseClassName(false); - this.setUseIdentityHashCode(false); - - this.setContentStart("{"); - this.setContentEnd("}"); - - this.setArrayStart("["); - this.setArrayEnd("]"); - - this.setFieldSeparator(","); - this.setFieldNameValueSeparator(":"); - - this.setNullText("null"); - - this.setSummaryObjectStartText("\"<"); - this.setSummaryObjectEndText(">\""); - - this.setSizeStartText("\"\""); - } - - @Override - public void append(final StringBuffer buffer, final String fieldName, final Object[] array, - final Boolean fullDetail) { - - if (fieldName == null) { - throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); - } - if (!isFullDetail(fullDetail)) { - throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); - } - - super.append(buffer, fieldName, array, fullDetail); - } - - @Override - public void append(final StringBuffer buffer, final String fieldName, final long[] array, - final Boolean fullDetail) { - - if (fieldName == null) { - throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); - } - if (!isFullDetail(fullDetail)) { - throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); - } - - super.append(buffer, fieldName, array, fullDetail); - } - - @Override - public void append(final StringBuffer buffer, final String fieldName, final int[] array, - final Boolean fullDetail) { - - if (fieldName == null) { - throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); - } - if (!isFullDetail(fullDetail)) { - throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); - } - - super.append(buffer, fieldName, array, fullDetail); - } - - @Override - public void append(final StringBuffer buffer, final String fieldName, final short[] array, - final Boolean fullDetail) { - - if (fieldName == null) { - throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); - } - if (!isFullDetail(fullDetail)) { - throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); - } - - super.append(buffer, fieldName, array, fullDetail); - } - - @Override - public void append(final StringBuffer buffer, final String fieldName, final byte[] array, - final Boolean fullDetail) { - - if (fieldName == null) { - throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); - } - if (!isFullDetail(fullDetail)) { - throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); - } - - super.append(buffer, fieldName, array, fullDetail); - } - - @Override - public void append(final StringBuffer buffer, final String fieldName, final char[] array, - final Boolean fullDetail) { - - if (fieldName == null) { - throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); - } - if (!isFullDetail(fullDetail)) { - throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); - } - - super.append(buffer, fieldName, array, fullDetail); - } - - @Override - public void append(final StringBuffer buffer, final String fieldName, final double[] array, - final Boolean fullDetail) { - - if (fieldName == null) { - throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); - } - if (!isFullDetail(fullDetail)) { - throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); - } - - super.append(buffer, fieldName, array, fullDetail); - } - - @Override - public void append(final StringBuffer buffer, final String fieldName, final float[] array, - final Boolean fullDetail) { - - if (fieldName == null) { - throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); - } - if (!isFullDetail(fullDetail)) { - throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); - } - - super.append(buffer, fieldName, array, fullDetail); - } - - @Override - public void append(final StringBuffer buffer, final String fieldName, final boolean[] array, - final Boolean fullDetail) { - - if (fieldName == null) { - throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); - } - if (!isFullDetail(fullDetail)) { - throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); - } - - super.append(buffer, fieldName, array, fullDetail); - } - - @Override - public void append(final StringBuffer buffer, final String fieldName, final Object value, - final Boolean fullDetail) { - - if (fieldName == null) { - throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); - } - if (!isFullDetail(fullDetail)) { - throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); - } - - super.append(buffer, fieldName, value, fullDetail); - } - - @Override - protected void appendDetail(final StringBuffer buffer, final String fieldName, final char value) { - appendValueAsString(buffer, String.valueOf(value)); - } - - @Override - protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { - - if (value == null) { - appendNullText(buffer, fieldName); - return; - } - - if (value instanceof String || value instanceof Character) { - appendValueAsString(buffer, value.toString()); - return; - } - - if (value instanceof Number || value instanceof Boolean) { - buffer.append(value); - return; - } - - final String valueAsString = value.toString(); - if (isJsonObject(valueAsString) || isJsonArray(valueAsString)) { - buffer.append(value); - return; - } - - appendDetail(buffer, fieldName, valueAsString); - } - - @Override - protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection coll) { - if (coll != null && !coll.isEmpty()) { - buffer.append(getArrayStart()); - int i = 0; - for (final Object item : coll) { - appendDetail(buffer, fieldName, i++, item); - } - buffer.append(getArrayEnd()); - return; - } - - buffer.append(coll); - } - - @Override - protected void appendDetail(final StringBuffer buffer, final String fieldName, final Map map) { - if (map != null && !map.isEmpty()) { - buffer.append(getContentStart()); - - boolean firstItem = true; - for (final Entry entry : map.entrySet()) { - final String keyStr = Objects.toString(entry.getKey(), null); - if (keyStr != null) { - if (firstItem) { - firstItem = false; - } else { - appendFieldEnd(buffer, keyStr); - } - appendFieldStart(buffer, keyStr); - final Object value = entry.getValue(); - if (value == null) { - appendNullText(buffer, keyStr); - } else { - appendInternal(buffer, keyStr, value, true); - } - } - } - - buffer.append(getContentEnd()); - return; - } - - buffer.append(map); - } - - private boolean isJsonArray(final String valueAsString) { - return valueAsString.startsWith(getArrayStart()) && valueAsString.endsWith(getArrayEnd()); - } - - private boolean isJsonObject(final String valueAsString) { - return valueAsString.startsWith(getContentStart()) && valueAsString.endsWith(getContentEnd()); - } - - /** - * Appends the given String enclosed in double-quotes to the given StringBuffer. - * - * @param buffer the StringBuffer to append the value to. - * @param value the value to append. - */ - private void appendValueAsString(final StringBuffer buffer, final String value) { - // buffer.append('"').append(StringEscapeUtils.escapeJson(value)).append('"'); - throw new UnsupportedOperationException("Not supported in TeaVM"); - } - - @Override - protected void appendFieldStart(final StringBuffer buffer, final String fieldName) { - throw new UnsupportedOperationException("Not supported in TeaVM"); - /* - * if (fieldName == null) { throw new UnsupportedOperationException( - * "Field names are mandatory when using JsonToStringStyle"); } - * - * super.appendFieldStart(buffer, FIELD_NAME_QUOTE + - * StringEscapeUtils.escapeJson(fieldName) + FIELD_NAME_QUOTE); - */ - } - - /** - *

- * Ensure {@code Singleton} after serialization. - *

- * - * @return the singleton - */ - private Object readResolve() { - return JSON_STYLE; - } - - } -} diff --git a/sources/main/java/org/apache/commons/lang3/builder/ToStringSummary.java b/sources/main/java/org/apache/commons/lang3/builder/ToStringSummary.java deleted file mode 100644 index d70f5594..00000000 --- a/sources/main/java/org/apache/commons/lang3/builder/ToStringSummary.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.builder; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Use this annotation on the fields to get the summary instead of the detailed - * information when using {@link ReflectionToStringBuilder}. - * - *

- * Notice that not all {@link ToStringStyle} implementations support the - * appendSummary method. - *

- * - * @since 3.8 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ToStringSummary { - // empty -} diff --git a/sources/main/java/org/apache/commons/lang3/compare/ComparableUtils.java b/sources/main/java/org/apache/commons/lang3/compare/ComparableUtils.java deleted file mode 100644 index 467c0262..00000000 --- a/sources/main/java/org/apache/commons/lang3/compare/ComparableUtils.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.compare; - -import java.util.function.Predicate; - -/** - *

- * Utility library to provide helper methods for translating - * {@link Comparable#compareTo} result into a boolean. - *

- * - *

- * Example: - * {@code boolean x = is(myComparable).lessThanOrEqualTo(otherComparable)} - *

- * - *

- * #ThreadSafe# - *

- * - * @since 3.10 - */ -public class ComparableUtils { - - /** - * Provides access to the available methods - * - * @param the type of objects that this object may be compared against. - */ - public static class ComparableCheckBuilder> { - - private final A a; - - private ComparableCheckBuilder(final A a) { - this.a = a; - } - - /** - * Checks if {@code [b <= a <= c]} or {@code [b >= a >= c]} where the {@code a} - * is object passed to {@link #is}. - * - * @param b the object to compare to the base object - * @param c the object to compare to the base object - * @return true if the base object is between b and c - */ - public boolean between(final A b, final A c) { - return betweenOrdered(b, c) || betweenOrdered(c, b); - } - - /** - * Checks if {@code (b < a < c)} or {@code (b > a > c)} where the {@code a} is - * object passed to {@link #is}. - * - * @param b the object to compare to the base object - * @param c the object to compare to the base object - * @return true if the base object is between b and c and not equal to those - */ - public boolean betweenExclusive(final A b, final A c) { - return betweenOrderedExclusive(b, c) || betweenOrderedExclusive(c, b); - } - - private boolean betweenOrdered(final A b, final A c) { - return greaterThanOrEqualTo(b) && lessThanOrEqualTo(c); - } - - private boolean betweenOrderedExclusive(final A b, final A c) { - return greaterThan(b) && lessThan(c); - } - - /** - * Checks if the object passed to {@link #is} is equal to {@code b} - * - * @param b the object to compare to the base object - * @return true if the value returned by {@link Comparable#compareTo} is equal - * to {@code 0} - */ - public boolean equalTo(final A b) { - return a.compareTo(b) == 0; - } - - /** - * Checks if the object passed to {@link #is} is greater than {@code b} - * - * @param b the object to compare to the base object - * @return true if the value returned by {@link Comparable#compareTo} is greater - * than {@code 0} - */ - public boolean greaterThan(final A b) { - return a.compareTo(b) > 0; - } - - /** - * Checks if the object passed to {@link #is} is greater than or equal to - * {@code b} - * - * @param b the object to compare to the base object - * @return true if the value returned by {@link Comparable#compareTo} is greater - * than or equal to {@code 0} - */ - public boolean greaterThanOrEqualTo(final A b) { - return a.compareTo(b) >= 0; - } - - /** - * Checks if the object passed to {@link #is} is less than {@code b} - * - * @param b the object to compare to the base object - * @return true if the value returned by {@link Comparable#compareTo} is less - * than {@code 0} - */ - public boolean lessThan(final A b) { - return a.compareTo(b) < 0; - } - - /** - * Checks if the object passed to {@link #is} is less than or equal to {@code b} - * - * @param b the object to compare to the base object - * @return true if the value returned by {@link Comparable#compareTo} is less - * than or equal to {@code 0} - */ - public boolean lessThanOrEqualTo(final A b) { - return a.compareTo(b) <= 0; - } - } - - /** - * Checks if {@code [b <= a <= c]} or {@code [b >= a >= c]} where the {@code a} - * is the tested object. - * - * @param b the object to compare to the tested object - * @param c the object to compare to the tested object - * @param type of the test object - * @return a predicate for true if the tested object is between b and c - */ - public static > Predicate between(final A b, final A c) { - return a -> is(a).between(b, c); - } - - /** - * Checks if {@code (b < a < c)} or {@code (b > a > c)} where the {@code a} is - * the tested object. - * - * @param b the object to compare to the tested object - * @param c the object to compare to the tested object - * @param type of the test object - * @return a predicate for true if the tested object is between b and c and not - * equal to those - */ - public static > Predicate betweenExclusive(final A b, final A c) { - return a -> is(a).betweenExclusive(b, c); - } - - /** - * Checks if the tested object is greater than or equal to {@code b} - * - * @param b the object to compare to the tested object - * @param type of the test object - * @return a predicate for true if the value returned by - * {@link Comparable#compareTo} is greater than or equal to {@code 0} - */ - public static > Predicate ge(final A b) { - return a -> is(a).greaterThanOrEqualTo(b); - } - - /** - * Checks if the tested object is greater than {@code b} - * - * @param b the object to compare to the tested object - * @param type of the test object - * @return a predicate for true if the value returned by - * {@link Comparable#compareTo} is greater than {@code 0} - */ - public static > Predicate gt(final A b) { - return a -> is(a).greaterThan(b); - } - - /** - * Provides access to the available methods - * - * @param a base object in the further comparison - * @param type of the base object - * @return a builder object with further methods - */ - public static > ComparableCheckBuilder is(final A a) { - return new ComparableCheckBuilder<>(a); - } - - /** - * Checks if the tested object is less than or equal to {@code b} - * - * @param b the object to compare to the tested object - * @param type of the test object - * @return a predicate for true if the value returned by - * {@link Comparable#compareTo} is less than or equal to {@code 0} - */ - public static > Predicate le(final A b) { - return a -> is(a).lessThanOrEqualTo(b); - } - - /** - * Checks if the tested object is less than {@code b} - * - * @param b the object to compare to the tested object - * @param type of the test object - * @return a predicate for true if the value returned by - * {@link Comparable#compareTo} is less than {@code 0} - */ - public static > Predicate lt(final A b) { - return a -> is(a).lessThan(b); - } - - private ComparableUtils() { - } -} diff --git a/sources/main/java/org/apache/commons/lang3/compare/ObjectToStringComparator.java b/sources/main/java/org/apache/commons/lang3/compare/ObjectToStringComparator.java deleted file mode 100644 index 1e6f59c5..00000000 --- a/sources/main/java/org/apache/commons/lang3/compare/ObjectToStringComparator.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.compare; - -import java.io.Serializable; -import java.util.Comparator; - -/** - * Compares Object's {@link Object#toString()} values. - * - * This class is stateless. - * - * @since 3.10 - */ -public final class ObjectToStringComparator implements Comparator, Serializable { - - /** - * Singleton instance. - * - * This class is stateless. - */ - public static final ObjectToStringComparator INSTANCE = new ObjectToStringComparator(); - - /** - * For {@link Serializable}. - */ - private static final long serialVersionUID = 1L; - - @Override - public int compare(final Object o1, final Object o2) { - if (o1 == null && o2 == null) { - return 0; - } - if (o1 == null) { - return 1; - } - if (o2 == null) { - return -1; - } - final String string1 = o1.toString(); - final String string2 = o2.toString(); - // No guarantee that toString() returns a non-null value, despite what Spotbugs - // thinks. - if (string1 == null && string2 == null) { - return 0; - } - if (string1 == null) { - return 1; - } - if (string2 == null) { - return -1; - } - return string1.compareTo(string2); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/compare/package-info.java b/sources/main/java/org/apache/commons/lang3/compare/package-info.java deleted file mode 100644 index 345111fe..00000000 --- a/sources/main/java/org/apache/commons/lang3/compare/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Provides classes to work with the {@link java.lang.Comparable} and - * {@link java.util.Comparator} interfaces. - * - * @since 3.10 - */ -package org.apache.commons.lang3.compare; diff --git a/sources/main/java/org/apache/commons/lang3/exception/CloneFailedException.java b/sources/main/java/org/apache/commons/lang3/exception/CloneFailedException.java deleted file mode 100644 index 64c4fefc..00000000 --- a/sources/main/java/org/apache/commons/lang3/exception/CloneFailedException.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.exception; - -/** - * Exception thrown when a clone cannot be created. In contrast to - * {@link CloneNotSupportedException} this is a {@link RuntimeException}. - * - * @since 3.0 - */ -public class CloneFailedException extends RuntimeException { - // ~ Static fields/initializers --------------------------------------------- - - private static final long serialVersionUID = 20091223L; - - // ~ Constructors ----------------------------------------------------------- - - /** - * Constructs a CloneFailedException. - * - * @param message description of the exception - */ - public CloneFailedException(final String message) { - super(message); - } - - /** - * Constructs a CloneFailedException. - * - * @param cause cause of the exception - */ - public CloneFailedException(final Throwable cause) { - super(cause); - } - - /** - * Constructs a CloneFailedException. - * - * @param message description of the exception - * @param cause cause of the exception - */ - public CloneFailedException(final String message, final Throwable cause) { - super(message, cause); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/exception/package-info.java b/sources/main/java/org/apache/commons/lang3/exception/package-info.java deleted file mode 100644 index caa2f255..00000000 --- a/sources/main/java/org/apache/commons/lang3/exception/package-info.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - *

- * Provides functionality for Exceptions. - *

- *

- * Contains the concept of an exception with context i.e. such an exception will - * contain a map with keys and values. This provides an easy way to pass - * valuable state information at exception time in useful form to a calling - * process. - *

- *

- * Lastly, {@link org.apache.commons.lang3.exception.ExceptionUtils} also - * contains {@code Throwable} manipulation and examination routines. - *

- * - * @since 1.0 - */ -package org.apache.commons.lang3.exception; diff --git a/sources/main/java/org/apache/commons/lang3/function/Failable.java b/sources/main/java/org/apache/commons/lang3/function/Failable.java deleted file mode 100644 index 9b71c8ed..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/Failable.java +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.lang.reflect.UndeclaredThrowableException; -import java.util.Collection; -import java.util.Objects; -import java.util.concurrent.Callable; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Stream; - -import org.apache.commons.lang3.stream.Streams.FailableStream; - -/** - * This class provides utility functions, and classes for working with the - * {@code java.util.function} package, or more generally, with Java 8 lambdas. - * More specifically, it attempts to address the fact that lambdas are supposed - * not to throw Exceptions, at least not checked Exceptions, AKA instances of - * {@link Exception}. This enforces the use of constructs like: - * - *
- * Consumer<java.lang.reflect.Method-> consumer = m -> {
- *     try {
- *         m.invoke(o, args);
- *     } catch (Throwable t) {
- *         throw Failable.rethrow(t);
- *     }
- * };
- * 
- * - *

- * By replacing a {@link java.util.function.Consumer Consumer<O>} with a - * {@link FailableConsumer FailableConsumer<O,? extends Throwable>}, this - * can be written like follows: - *

- * - *
- * Functions.accept((m) -> m.invoke(o, args));
- * 
- * - *

- * Obviously, the second version is much more concise and the spirit of Lambda - * expressions is met better than the second version. - *

- * - * @since 3.11 - */ -public class Failable { - - /** - * Consumes a consumer and rethrows any exception as a {@link RuntimeException}. - * - * @param consumer the consumer to consume - * @param object1 the first object to consume by {@code consumer} - * @param object2 the second object to consume by {@code consumer} - * @param the type of the first argument the consumer accepts - * @param the type of the second argument the consumer accepts - * @param the type of checked exception the consumer may throw - */ - public static void accept(final FailableBiConsumer consumer, final T object1, - final U object2) { - run(() -> consumer.accept(object1, object2)); - } - - /** - * Consumes a consumer and rethrows any exception as a {@link RuntimeException}. - * - * @param consumer the consumer to consume - * @param object the object to consume by {@code consumer} - * @param the type the consumer accepts - * @param the type of checked exception the consumer may throw - */ - public static void accept(final FailableConsumer consumer, final T object) { - run(() -> consumer.accept(object)); - } - - /** - * Consumes a consumer and rethrows any exception as a {@link RuntimeException}. - * - * @param consumer the consumer to consume - * @param value the value to consume by {@code consumer} - * @param the type of checked exception the consumer may throw - */ - public static void accept(final FailableDoubleConsumer consumer, final double value) { - run(() -> consumer.accept(value)); - } - - /** - * Consumes a consumer and rethrows any exception as a {@link RuntimeException}. - * - * @param consumer the consumer to consume - * @param value the value to consume by {@code consumer} - * @param the type of checked exception the consumer may throw - */ - public static void accept(final FailableIntConsumer consumer, final int value) { - run(() -> consumer.accept(value)); - } - - /** - * Consumes a consumer and rethrows any exception as a {@link RuntimeException}. - * - * @param consumer the consumer to consume - * @param value the value to consume by {@code consumer} - * @param the type of checked exception the consumer may throw - */ - public static void accept(final FailableLongConsumer consumer, final long value) { - run(() -> consumer.accept(value)); - } - - /** - * Applies a function and rethrows any exception as a {@link RuntimeException}. - * - * @param function the function to apply - * @param input1 the first input to apply {@code function} on - * @param input2 the second input to apply {@code function} on - * @param the type of the first argument the function accepts - * @param the type of the second argument the function accepts - * @param the return type of the function - * @param the type of checked exception the function may throw - * @return the value returned from the function - */ - public static R apply(final FailableBiFunction function, final T input1, - final U input2) { - return get(() -> function.apply(input1, input2)); - } - - /** - * Applies a function and rethrows any exception as a {@link RuntimeException}. - * - * @param function the function to apply - * @param input the input to apply {@code function} on - * @param the type of the argument the function accepts - * @param the return type of the function - * @param the type of checked exception the function may throw - * @return the value returned from the function - */ - public static R apply(final FailableFunction function, final T input) { - return get(() -> function.apply(input)); - } - - /** - * Applies a function and rethrows any exception as a {@link RuntimeException}. - * - * @param function the function to apply - * @param left the first input to apply {@code function} on - * @param right the second input to apply {@code function} on - * @param the type of checked exception the function may throw - * @return the value returned from the function - */ - public static double applyAsDouble(final FailableDoubleBinaryOperator function, - final double left, final double right) { - return getAsDouble(() -> function.applyAsDouble(left, right)); - } - - /** - * Converts the given {@link FailableBiConsumer} into a standard - * {@link BiConsumer}. - * - * @param the type of the first argument of the consumers - * @param the type of the second argument of the consumers - * @param consumer a failable {@code BiConsumer} - * @return a standard {@code BiConsumer} - */ - public static BiConsumer asBiConsumer(final FailableBiConsumer consumer) { - return (input1, input2) -> accept(consumer, input1, input2); - } - - /** - * Converts the given {@link FailableBiFunction} into a standard - * {@link BiFunction}. - * - * @param the type of the first argument of the input of the functions - * @param the type of the second argument of the input of the functions - * @param the type of the output of the functions - * @param function a {@code FailableBiFunction} - * @return a standard {@code BiFunction} - */ - public static BiFunction asBiFunction(final FailableBiFunction function) { - return (input1, input2) -> apply(function, input1, input2); - } - - /** - * Converts the given {@link FailableBiPredicate} into a standard - * {@link BiPredicate}. - * - * @param the type of the first argument used by the predicates - * @param the type of the second argument used by the predicates - * @param predicate a {@code FailableBiPredicate} - * @return a standard {@code BiPredicate} - */ - public static BiPredicate asBiPredicate(final FailableBiPredicate predicate) { - return (input1, input2) -> test(predicate, input1, input2); - } - - /** - * Converts the given {@link FailableCallable} into a standard {@link Callable}. - * - * @param the type used by the callables - * @param callable a {@code FailableCallable} - * @return a standard {@code Callable} - */ - public static Callable asCallable(final FailableCallable callable) { - return () -> call(callable); - } - - /** - * Converts the given {@link FailableConsumer} into a standard {@link Consumer}. - * - * @param the type used by the consumers - * @param consumer a {@code FailableConsumer} - * @return a standard {@code Consumer} - */ - public static Consumer asConsumer(final FailableConsumer consumer) { - return input -> accept(consumer, input); - } - - /** - * Converts the given {@link FailableFunction} into a standard {@link Function}. - * - * @param the type of the input of the functions - * @param the type of the output of the functions - * @param function a {code FailableFunction} - * @return a standard {@code Function} - */ - public static Function asFunction(final FailableFunction function) { - return input -> apply(function, input); - } - - /** - * Converts the given {@link FailablePredicate} into a standard - * {@link Predicate}. - * - * @param the type used by the predicates - * @param predicate a {@code FailablePredicate} - * @return a standard {@code Predicate} - */ - public static Predicate asPredicate(final FailablePredicate predicate) { - return input -> test(predicate, input); - } - - /** - * Converts the given {@link FailableRunnable} into a standard {@link Runnable}. - * - * @param runnable a {@code FailableRunnable} - * @return a standard {@code Runnable} - */ - public static Runnable asRunnable(final FailableRunnable runnable) { - return () -> run(runnable); - } - - /** - * Converts the given {@link FailableSupplier} into a standard {@link Supplier}. - * - * @param the type supplied by the suppliers - * @param supplier a {@code FailableSupplier} - * @return a standard {@code Supplier} - */ - public static Supplier asSupplier(final FailableSupplier supplier) { - return () -> get(supplier); - } - - /** - * Calls a callable and rethrows any exception as a {@link RuntimeException}. - * - * @param callable the callable to call - * @param the return type of the callable - * @param the type of checked exception the callable may throw - * @return the value returned from the callable - */ - public static V call(final FailableCallable callable) { - return get(callable::call); - } - - /** - * Invokes a supplier, and returns the result. - * - * @param supplier The supplier to invoke. - * @param The suppliers output type. - * @param The type of checked exception, which the supplier can throw. - * @return The object, which has been created by the supplier - */ - public static T get(final FailableSupplier supplier) { - try { - return supplier.get(); - } catch (final Throwable t) { - throw rethrow(t); - } - } - - /** - * Invokes a boolean supplier, and returns the result. - * - * @param supplier The boolean supplier to invoke. - * @param The type of checked exception, which the supplier can throw. - * @return The boolean, which has been created by the supplier - */ - public static boolean getAsBoolean(final FailableBooleanSupplier supplier) { - try { - return supplier.getAsBoolean(); - } catch (final Throwable t) { - throw rethrow(t); - } - } - - /** - * Invokes a double supplier, and returns the result. - * - * @param supplier The double supplier to invoke. - * @param The type of checked exception, which the supplier can throw. - * @return The double, which has been created by the supplier - */ - public static double getAsDouble(final FailableDoubleSupplier supplier) { - try { - return supplier.getAsDouble(); - } catch (final Throwable t) { - throw rethrow(t); - } - } - - /** - * Invokes an int supplier, and returns the result. - * - * @param supplier The int supplier to invoke. - * @param The type of checked exception, which the supplier can throw. - * @return The int, which has been created by the supplier - */ - public static int getAsInt(final FailableIntSupplier supplier) { - try { - return supplier.getAsInt(); - } catch (final Throwable t) { - throw rethrow(t); - } - } - - /** - * Invokes a long supplier, and returns the result. - * - * @param supplier The long supplier to invoke. - * @param The type of checked exception, which the supplier can throw. - * @return The long, which has been created by the supplier - */ - public static long getAsLong(final FailableLongSupplier supplier) { - try { - return supplier.getAsLong(); - } catch (final Throwable t) { - throw rethrow(t); - } - } - - /** - * Invokes a short supplier, and returns the result. - * - * @param supplier The short supplier to invoke. - * @param The type of checked exception, which the supplier can throw. - * @return The short, which has been created by the supplier - */ - public static short getAsShort(final FailableShortSupplier supplier) { - try { - return supplier.getAsShort(); - } catch (final Throwable t) { - throw rethrow(t); - } - } - - /** - *

- * Rethrows a {@link Throwable} as an unchecked exception. If the argument is - * already unchecked, namely a {@code RuntimeException} or {@code Error} then - * the argument will be rethrown without modification. If the exception is - * {@code IOException} then it will be wrapped into a - * {@code UncheckedIOException}. In every other cases the exception will be - * wrapped into a {@code - * UndeclaredThrowableException} - *

- * - *

- * Note that there is a declared return type for this method, even though it - * never returns. The reason for that is to support the usual pattern: - *

- * - *
-	 * throw rethrow(myUncheckedException);
-	 * 
- * - *

- * instead of just calling the method. This pattern may help the Java compiler - * to recognize that at that point an exception will be thrown and the code flow - * analysis will not demand otherwise mandatory commands that could follow the - * method call, like a {@code return} statement from a value returning method. - *

- * - * @param throwable The throwable to rethrow ossibly wrapped into an unchecked - * exception - * @return Never returns anything, this method never terminates normally. - */ - public static RuntimeException rethrow(final Throwable throwable) { - Objects.requireNonNull(throwable, "throwable"); - if (throwable instanceof RuntimeException) { - throw (RuntimeException) throwable; - } else if (throwable instanceof Error) { - throw (Error) throwable; - } else if (throwable instanceof IOException) { - throw new UncheckedIOException((IOException) throwable); - } else { - throw new UndeclaredThrowableException(throwable); - } - } - - /** - * Runs a runnable and rethrows any exception as a {@link RuntimeException}. - * - * @param runnable The runnable to run - * @param the type of checked exception the runnable may throw - */ - public static void run(final FailableRunnable runnable) { - try { - runnable.run(); - } catch (final Throwable t) { - throw rethrow(t); - } - } - - /** - * Converts the given collection into a {@link FailableStream}. The - * {@link FailableStream} consists of the collections elements. Shortcut for - * - *
-	 * Functions.stream(collection.stream());
-	 * 
- * - * @param collection The collection, which is being converted into a - * {@link FailableStream}. - * @param The collections element type. (In turn, the result streams - * element type.) - * @return The created {@link FailableStream}. - */ - public static FailableStream stream(final Collection collection) { - return new FailableStream<>(collection.stream()); - } - - /** - * Converts the given stream into a {@link FailableStream}. The - * {@link FailableStream} consists of the same elements, than the input stream. - * However, failable lambdas, like {@link FailablePredicate}, - * {@link FailableFunction}, and {@link FailableConsumer} may be applied, rather - * than {@link Predicate}, {@link Function}, {@link Consumer}, etc. - * - * @param stream The stream, which is being converted into a - * {@link FailableStream}. - * @param The streams element type. - * @return The created {@link FailableStream}. - */ - public static FailableStream stream(final Stream stream) { - return new FailableStream<>(stream); - } - - /** - * Tests a predicate and rethrows any exception as a {@link RuntimeException}. - * - * @param predicate the predicate to test - * @param object1 the first input to test by {@code predicate} - * @param object2 the second input to test by {@code predicate} - * @param the type of the first argument the predicate tests - * @param the type of the second argument the predicate tests - * @param the type of checked exception the predicate may throw - * @return the boolean value returned by the predicate - */ - public static boolean test(final FailableBiPredicate predicate, - final T object1, final U object2) { - return getAsBoolean(() -> predicate.test(object1, object2)); - } - - /** - * Tests a predicate and rethrows any exception as a {@link RuntimeException}. - * - * @param predicate the predicate to test - * @param object the input to test by {@code predicate} - * @param the type of argument the predicate tests - * @param the type of checked exception the predicate may throw - * @return the boolean value returned by the predicate - */ - public static boolean test(final FailablePredicate predicate, final T object) { - return getAsBoolean(() -> predicate.test(object)); - } - - /** - * A simple try-with-resources implementation, that can be used, if your objects - * do not implement the {@link AutoCloseable} interface. The method executes the - * {@code action}. The method guarantees, that all the - * {@code resources} are being executed, in the given order, afterwards, and - * regardless of success, or failure. If either the original action, or any of - * the resource action fails, then the first failure (AKA - * {@link Throwable} is rethrown. Example use: - * - *
-	 * final FileInputStream fis = new FileInputStream("my.file");
-	 * Functions.tryWithResources(useInputStream(fis), null, () -> fis.close());
-	 * 
- * - * @param action The action to execute. This object will always - * be invoked. - * @param errorHandler An optional error handler, which will be invoked finally, - * if any error occurred. The error handler will receive the - * first error, AKA {@link Throwable}. - * @param resources The resource actions to execute. All resource - * actions will be invoked, in the given order. A resource - * action is an instance of {@link FailableRunnable}, which - * will be executed. - * @see #tryWithResources(FailableRunnable, FailableRunnable...) - */ - @SafeVarargs - public static void tryWithResources(final FailableRunnable action, - final FailableConsumer errorHandler, - final FailableRunnable... resources) { - final FailableConsumer actualErrorHandler; - if (errorHandler == null) { - actualErrorHandler = Failable::rethrow; - } else { - actualErrorHandler = errorHandler; - } - if (resources != null) { - for (final FailableRunnable failableRunnable : resources) { - Objects.requireNonNull(failableRunnable, "runnable"); - } - } - Throwable th = null; - try { - action.run(); - } catch (final Throwable t) { - th = t; - } - if (resources != null) { - for (final FailableRunnable runnable : resources) { - try { - runnable.run(); - } catch (final Throwable t) { - if (th == null) { - th = t; - } - } - } - } - if (th != null) { - try { - actualErrorHandler.accept(th); - } catch (final Throwable t) { - throw rethrow(t); - } - } - } - - /** - * A simple try-with-resources implementation, that can be used, if your objects - * do not implement the {@link AutoCloseable} interface. The method executes the - * {@code action}. The method guarantees, that all the - * {@code resources} are being executed, in the given order, afterwards, and - * regardless of success, or failure. If either the original action, or any of - * the resource action fails, then the first failure (AKA - * {@link Throwable} is rethrown. Example use: - * - *
-	 * final FileInputStream fis = new FileInputStream("my.file");
-	 * Functions.tryWithResources(useInputStream(fis), () -> fis.close());
-	 * 
- * - * @param action The action to execute. This object will always be - * invoked. - * @param resources The resource actions to execute. All resource - * actions will be invoked, in the given order. A resource - * action is an instance of {@link FailableRunnable}, which - * will be executed. - * @see #tryWithResources(FailableRunnable, FailableConsumer, - * FailableRunnable...) - */ - @SafeVarargs - public static void tryWithResources(final FailableRunnable action, - final FailableRunnable... resources) { - tryWithResources(action, null, resources); - } - - private Failable() { - // empty - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableBiConsumer.java b/sources/main/java/org/apache/commons/lang3/function/FailableBiConsumer.java deleted file mode 100644 index b3b74e82..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableBiConsumer.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A functional interface like {@link BiConsumer} that declares a - * {@code Throwable}. - * - * @param Consumed type 1. - * @param Consumed type 2. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableBiConsumer { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableBiConsumer NOP = (t, u) -> { - /* NOP */}; - - /** - * Returns The NOP singleton. - * - * @param Consumed type 1. - * @param Consumed type 2. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableBiConsumer nop() { - return NOP; - } - - /** - * Accepts the consumer. - * - * @param t the first parameter for the consumable to accept - * @param u the second parameter for the consumable to accept - * @throws E Thrown when the consumer fails. - */ - void accept(T t, U u) throws E; - - /** - * Returns a composed {@code FailableBiConsumer} like - * {@link BiConsumer#andThen(BiConsumer)}. - * - * @param after the operation to perform after this one. - * @return a composed {@code FailableBiConsumer} like - * {@link BiConsumer#andThen(BiConsumer)}. - * @throws NullPointerException when {@code after} is null. - */ - default FailableBiConsumer andThen(final FailableBiConsumer after) { - Objects.requireNonNull(after); - return (t, u) -> { - accept(t, u); - after.accept(t, u); - }; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableBiFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableBiFunction.java deleted file mode 100644 index 99475b60..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableBiFunction.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.BiFunction; -import java.util.function.Function; - -/** - * A functional interface like {@link BiFunction} that declares a - * {@code Throwable}. - * - * @param Input type 1. - * @param Input type 2. - * @param Return type. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableBiFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableBiFunction NOP = (t, u) -> null; - - /** - * Returns The NOP singleton. - * - * @param Consumed type 1. - * @param Consumed type 2. - * @param Return type. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableBiFunction nop() { - return NOP; - } - - /** - * Returns a composed {@code FailableBiFunction} that like - * {@link BiFunction#andThen(Function)}. - * - * @param the output type of the {@code after} function, and of the - * composed function. - * @param after the operation to perform after this one. - * @return a composed {@code FailableBiFunction} that like - * {@link BiFunction#andThen(Function)}. - * @throws NullPointerException when {@code after} is null. - */ - default FailableBiFunction andThen(final FailableFunction after) { - Objects.requireNonNull(after); - return (final T t, final U u) -> after.apply(apply(t, u)); - } - - /** - * Applies this function. - * - * @param input1 the first input for the function - * @param input2 the second input for the function - * @return the result of the function - * @throws E Thrown when the function fails. - */ - R apply(T input1, U input2) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableBiPredicate.java b/sources/main/java/org/apache/commons/lang3/function/FailableBiPredicate.java deleted file mode 100644 index 21c92d7e..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableBiPredicate.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.BiPredicate; - -/** - * A functional interface like {@link BiPredicate} that declares a - * {@code Throwable}. - * - * @param Predicate type 1. - * @param Predicate type 2. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableBiPredicate { - - /** FALSE singleton */ - @SuppressWarnings("rawtypes") - FailableBiPredicate FALSE = (t, u) -> false; - - /** TRUE singleton */ - @SuppressWarnings("rawtypes") - FailableBiPredicate TRUE = (t, u) -> true; - - /** - * Returns The FALSE singleton. - * - * @param Consumed type 1. - * @param Consumed type 2. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableBiPredicate falsePredicate() { - return FALSE; - } - - /** - * Returns The FALSE TRUE. - * - * @param Consumed type 1. - * @param Consumed type 2. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableBiPredicate truePredicate() { - return TRUE; - } - - /** - * Returns a composed {@code FailableBiPredicate} like - * {@link BiPredicate#and(BiPredicate)}. - * - * @param other a predicate that will be logically-ANDed with this predicate. - * @return a composed {@code FailableBiPredicate} like - * {@link BiPredicate#and(BiPredicate)}. - * @throws NullPointerException if other is null - */ - default FailableBiPredicate and(final FailableBiPredicate other) { - Objects.requireNonNull(other); - return (final T t, final U u) -> test(t, u) && other.test(t, u); - } - - /** - * Returns a predicate that negates this predicate. - * - * @return a predicate that negates this predicate. - */ - default FailableBiPredicate negate() { - return (final T t, final U u) -> !test(t, u); - } - - /** - * Returns a composed {@code FailableBiPredicate} like - * {@link BiPredicate#and(BiPredicate)}. - * - * @param other a predicate that will be logically-ORed with this predicate. - * @return a composed {@code FailableBiPredicate} like - * {@link BiPredicate#and(BiPredicate)}. - * @throws NullPointerException if other is null - */ - default FailableBiPredicate or(final FailableBiPredicate other) { - Objects.requireNonNull(other); - return (final T t, final U u) -> test(t, u) || other.test(t, u); - } - - /** - * Tests the predicate. - * - * @param object1 the first object to test the predicate on - * @param object2 the second object to test the predicate on - * @return the predicate's evaluation - * @throws E Thrown when this predicate fails. - */ - boolean test(T object1, U object2) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableBooleanSupplier.java b/sources/main/java/org/apache/commons/lang3/function/FailableBooleanSupplier.java deleted file mode 100644 index af57077e..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableBooleanSupplier.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.BooleanSupplier; - -/** - * A functional interface like {@link BooleanSupplier} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableBooleanSupplier { - - /** - * Supplies a boolean. - * - * @return a result - * @throws E if the supplier fails - */ - boolean getAsBoolean() throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableCallable.java b/sources/main/java/org/apache/commons/lang3/function/FailableCallable.java deleted file mode 100644 index 6d4ba608..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableCallable.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -/** - * A functional interface like {@link java.util.concurrent.Callable} that - * declares a {@code Throwable}. - * - * @param Return type. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableCallable { - - /** - * Calls the callable. - * - * @return The value returned from the callable - * @throws E if the callable fails - */ - R call() throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableConsumer.java b/sources/main/java/org/apache/commons/lang3/function/FailableConsumer.java deleted file mode 100644 index e4598e4d..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableConsumer.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.Consumer; - -/** - * A functional interface like {@link Consumer} that declares a - * {@code Throwable}. - * - * @param Consumed type 1. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableConsumer { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableConsumer NOP = t -> { - /* NOP */}; - - /** - * Returns The NOP singleton. - * - * @param Consumed type 1. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableConsumer nop() { - return NOP; - } - - /** - * Accepts the consumer. - * - * @param object the parameter for the consumable to accept - * @throws E Thrown when the consumer fails. - */ - void accept(T object) throws E; - - /** - * Returns a composed {@code Consumer} like {@link Consumer#andThen(Consumer)}. - * - * @param after the operation to perform after this operation - * @return a composed {@code Consumer} like {@link Consumer#andThen(Consumer)}. - * @throws NullPointerException when {@code after} is null - */ - default FailableConsumer andThen(final FailableConsumer after) { - Objects.requireNonNull(after); - return (final T t) -> { - accept(t); - after.accept(t); - }; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleBinaryOperator.java b/sources/main/java/org/apache/commons/lang3/function/FailableDoubleBinaryOperator.java deleted file mode 100644 index e6e21e59..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleBinaryOperator.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.DoubleBinaryOperator; - -/** - * A functional interface like {@link DoubleBinaryOperator} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableDoubleBinaryOperator { - - /** - * Applies this operator to the given operands. - * - * @param left the first operand - * @param right the second operand - * @return the operator result - * @throws E if the operation fails - */ - double applyAsDouble(double left, double right) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleConsumer.java b/sources/main/java/org/apache/commons/lang3/function/FailableDoubleConsumer.java deleted file mode 100644 index 9b97b567..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleConsumer.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.DoubleConsumer; - -/** - * A functional interface like {@link DoubleConsumer} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableDoubleConsumer { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableDoubleConsumer NOP = t -> { - /* NOP */}; - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableDoubleConsumer nop() { - return NOP; - } - - /** - * Accepts the consumer. - * - * @param value the parameter for the consumable to accept - * @throws E Thrown when the consumer fails. - */ - void accept(double value) throws E; - - /** - * Returns a composed {@code FailableDoubleConsumer} like - * {@link DoubleConsumer#andThen(DoubleConsumer)}. - * - * @param after the operation to perform after this one. - * @return a composed {@code FailableDoubleConsumer} like - * {@link DoubleConsumer#andThen(DoubleConsumer)}. - * @throws NullPointerException when {@code after} is null. - */ - default FailableDoubleConsumer andThen(final FailableDoubleConsumer after) { - Objects.requireNonNull(after); - return (final double t) -> { - accept(t); - after.accept(t); - }; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableDoubleFunction.java deleted file mode 100644 index 927cbdd1..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleFunction.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.DoubleFunction; - -/** - * A functional interface like {@link DoubleFunction} that declares a - * {@code Throwable}. - * - * @param Return type. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableDoubleFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableDoubleFunction NOP = t -> null; - - /** - * Returns The NOP singleton. - * - * @param Return type. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableDoubleFunction nop() { - return NOP; - } - - /** - * Applies this function. - * - * @param input the input for the function - * @return the result of the function - * @throws E Thrown when the function fails. - */ - R apply(double input) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableDoublePredicate.java b/sources/main/java/org/apache/commons/lang3/function/FailableDoublePredicate.java deleted file mode 100644 index ccf43cff..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableDoublePredicate.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.DoublePredicate; - -/** - * A functional interface like {@link DoublePredicate} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableDoublePredicate { - - /** FALSE singleton */ - @SuppressWarnings("rawtypes") - FailableDoublePredicate FALSE = t -> false; - - /** TRUE singleton */ - @SuppressWarnings("rawtypes") - FailableDoublePredicate TRUE = t -> true; - - /** - * Returns The FALSE singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableDoublePredicate falsePredicate() { - return FALSE; - } - - /** - * Returns The FALSE TRUE. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableDoublePredicate truePredicate() { - return TRUE; - } - - /** - * Returns a composed {@code FailableDoublePredicate} like - * {@link DoublePredicate#and(DoublePredicate)}. - * - * @param other a predicate that will be logically-ANDed with this predicate. - * @return a composed {@code FailableDoublePredicate} like - * {@link DoublePredicate#and(DoublePredicate)}. - * @throws NullPointerException if other is null - */ - default FailableDoublePredicate and(final FailableDoublePredicate other) { - Objects.requireNonNull(other); - return t -> test(t) && other.test(t); - } - - /** - * Returns a predicate that negates this predicate. - * - * @return a predicate that negates this predicate. - */ - default FailableDoublePredicate negate() { - return t -> !test(t); - } - - /** - * Returns a composed {@code FailableDoublePredicate} like - * {@link DoublePredicate#and(DoublePredicate)}. - * - * @param other a predicate that will be logically-ORed with this predicate. - * @return a composed {@code FailableDoublePredicate} like - * {@link DoublePredicate#and(DoublePredicate)}. - * @throws NullPointerException if other is null - */ - default FailableDoublePredicate or(final FailableDoublePredicate other) { - Objects.requireNonNull(other); - return t -> test(t) || other.test(t); - } - - /** - * Tests the predicate. - * - * @param value the parameter for the predicate to accept. - * @return {@code true} if the input argument matches the predicate, - * {@code false} otherwise. - * @throws E Thrown when the consumer fails. - */ - boolean test(double value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleSupplier.java b/sources/main/java/org/apache/commons/lang3/function/FailableDoubleSupplier.java deleted file mode 100644 index e92d309f..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleSupplier.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.DoubleSupplier; - -/** - * A functional interface like {@link DoubleSupplier} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableDoubleSupplier { - - /** - * Supplies a double. - * - * @return a result - * @throws E if the supplier fails - */ - double getAsDouble() throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleToIntFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableDoubleToIntFunction.java deleted file mode 100644 index 27c6d8fc..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleToIntFunction.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.DoubleToIntFunction; - -/** - * A functional interface like {@link DoubleToIntFunction} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableDoubleToIntFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableDoubleToIntFunction NOP = t -> 0; - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableDoubleToIntFunction nop() { - return NOP; - } - - /** - * Applies this function to the given argument. - * - * @param value the function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - int applyAsInt(double value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleToLongFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableDoubleToLongFunction.java deleted file mode 100644 index 705c0c63..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleToLongFunction.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.DoubleToLongFunction; - -/** - * A functional interface like {@link DoubleToLongFunction} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableDoubleToLongFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableDoubleToLongFunction NOP = t -> 0; - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableDoubleToLongFunction nop() { - return NOP; - } - - /** - * Applies this function to the given argument. - * - * @param value the function argument - * @return the function result - * @throws E if the operation fails - */ - int applyAsLong(double value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleUnaryOperator.java b/sources/main/java/org/apache/commons/lang3/function/FailableDoubleUnaryOperator.java deleted file mode 100644 index 0503d443..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableDoubleUnaryOperator.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.DoubleUnaryOperator; - -/** - * A functional interface like {@link DoubleUnaryOperator} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -public interface FailableDoubleUnaryOperator { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableDoubleUnaryOperator NOP = t -> 0d; - - /** - * Returns a unary operator that always returns its input argument. - * - * @param Thrown exception. - * @return a unary operator that always returns its input argument - */ - static FailableDoubleUnaryOperator identity() { - return t -> t; - } - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableDoubleUnaryOperator nop() { - return NOP; - } - - /** - * Returns a composed {@code FailableDoubleUnaryOperator} like - * {@link DoubleUnaryOperator#andThen(DoubleUnaryOperator)}. - * - * @param after the operator to apply after this one. - * @return a composed {@code FailableDoubleUnaryOperator} like - * {@link DoubleUnaryOperator#andThen(DoubleUnaryOperator)}. - * @throws NullPointerException if after is null. - * @see #compose(FailableDoubleUnaryOperator) - */ - default FailableDoubleUnaryOperator andThen(final FailableDoubleUnaryOperator after) { - Objects.requireNonNull(after); - return (final double t) -> after.applyAsDouble(applyAsDouble(t)); - } - - /** - * Applies this operator to the given operand. - * - * @param operand the operand - * @return the operator result - * @throws E Thrown when a consumer fails. - */ - double applyAsDouble(double operand) throws E; - - /** - * Returns a composed {@code FailableDoubleUnaryOperator} like - * {@link DoubleUnaryOperator#compose(DoubleUnaryOperator)}. - * - * @param before the operator to apply before this one. - * @return a composed {@code FailableDoubleUnaryOperator} like - * {@link DoubleUnaryOperator#compose(DoubleUnaryOperator)}. - * @throws NullPointerException if before is null. - * @see #andThen(FailableDoubleUnaryOperator) - */ - default FailableDoubleUnaryOperator compose(final FailableDoubleUnaryOperator before) { - Objects.requireNonNull(before); - return (final double v) -> applyAsDouble(before.applyAsDouble(v)); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableFunction.java deleted file mode 100644 index b22385be..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableFunction.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.Function; - -/** - * A functional interface like {@link Function} that declares a - * {@code Throwable}. - * - * @param Input type 1. - * @param Return type. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableFunction NOP = t -> null; - - /** - * Returns a function that always returns its input argument. - * - * @param the type of the input and output objects to the function - * @param Thrown exception. - * @return a function that always returns its input argument - */ - static FailableFunction identity() { - return t -> t; - } - - /** - * Returns The NOP singleton. - * - * @param Consumed type 1. - * @param Return type. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableFunction nop() { - return NOP; - } - - /** - * Returns a composed {@code FailableFunction} like - * {@link Function#andThen(Function)}. - * - * @param the output type of the {@code after} function, and of the composed - * function. - * @return a composed {@code FailableFunction} like - * {@link Function#andThen(Function)}. - * @param after the operation to perform after this one. - * @throws NullPointerException when {@code after} is null. - */ - default FailableFunction andThen(final FailableFunction after) { - Objects.requireNonNull(after); - return (final T t) -> after.apply(apply(t)); - } - - /** - * Applies this function. - * - * @param input the input for the function - * @return the result of the function - * @throws E Thrown when the function fails. - */ - R apply(T input) throws E; - - /** - * Returns a composed {@code FailableFunction} like - * {@link Function#compose(Function)}. - * - * @param the input type to the {@code before} function, and to the - * composed function. - * @param before the operator to apply before this one. - * @return a a composed {@code FailableFunction} like - * {@link Function#compose(Function)}. - * @throws NullPointerException if before is null. - * @see #andThen(FailableFunction) - */ - default FailableFunction compose(final FailableFunction before) { - Objects.requireNonNull(before); - return (final V v) -> apply(before.apply(v)); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableIntBinaryOperator.java b/sources/main/java/org/apache/commons/lang3/function/FailableIntBinaryOperator.java deleted file mode 100644 index 2905a218..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableIntBinaryOperator.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.IntBinaryOperator; - -/** - * A functional interface like {@link IntBinaryOperator} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableIntBinaryOperator { - - /** - * Applies this operator to the given operands. - * - * @param left the first operand - * @param right the second operand - * @return the operator result - * @throws E if the operation fails - */ - int applyAsInt(int left, int right) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableIntConsumer.java b/sources/main/java/org/apache/commons/lang3/function/FailableIntConsumer.java deleted file mode 100644 index b9258883..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableIntConsumer.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.IntConsumer; - -/** - * A functional interface like {@link IntConsumer} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableIntConsumer { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableIntConsumer NOP = t -> { - /* NOP */}; - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableIntConsumer nop() { - return NOP; - } - - /** - * Accepts the consumer. - * - * @param value the parameter for the consumable to accept - * @throws E Thrown when the consumer fails. - */ - void accept(int value) throws E; - - /** - * Returns a composed {@code FailableIntConsumer} like - * {@link IntConsumer#andThen(IntConsumer)}. - * - * @param after the operation to perform after this one. - * @return a composed {@code FailableLongConsumer} like - * {@link IntConsumer#andThen(IntConsumer)}. - * @throws NullPointerException if {@code after} is null - */ - default FailableIntConsumer andThen(final FailableIntConsumer after) { - Objects.requireNonNull(after); - return (final int t) -> { - accept(t); - after.accept(t); - }; - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableIntFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableIntFunction.java deleted file mode 100644 index 84786d3b..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableIntFunction.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.IntFunction; - -/** - * A functional interface like {@link IntFunction} that declares a - * {@code Throwable}. - * - * @param Return type. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableIntFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableIntFunction NOP = t -> null; - - /** - * Returns The NOP singleton. - * - * @param Return type. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableIntFunction nop() { - return NOP; - } - - /** - * Applies this function. - * - * @param input the input for the function - * @return the result of the function - * @throws E Thrown when the function fails. - */ - R apply(int input) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableIntPredicate.java b/sources/main/java/org/apache/commons/lang3/function/FailableIntPredicate.java deleted file mode 100644 index 79843d6e..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableIntPredicate.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.IntPredicate; - -/** - * A functional interface like {@link IntPredicate} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableIntPredicate { - - /** FALSE singleton */ - @SuppressWarnings("rawtypes") - FailableIntPredicate FALSE = t -> false; - - /** TRUE singleton */ - @SuppressWarnings("rawtypes") - FailableIntPredicate TRUE = t -> true; - - /** - * Returns The FALSE singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableIntPredicate falsePredicate() { - return FALSE; - } - - /** - * Returns The FALSE TRUE. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableIntPredicate truePredicate() { - return TRUE; - } - - /** - * Returns a composed {@code FailableIntPredicate} like - * {@link IntPredicate#and(IntPredicate)}. - * - * @param other a predicate that will be logically-ANDed with this predicate. - * @return a composed {@code FailableIntPredicate} like - * {@link IntPredicate#and(IntPredicate)}. - * @throws NullPointerException if other is null - */ - default FailableIntPredicate and(final FailableIntPredicate other) { - Objects.requireNonNull(other); - return t -> test(t) && other.test(t); - } - - /** - * Returns a predicate that negates this predicate. - * - * @return a predicate that negates this predicate. - */ - default FailableIntPredicate negate() { - return t -> !test(t); - } - - /** - * Returns a composed {@code FailableIntPredicate} like - * {@link IntPredicate#and(IntPredicate)}. - * - * @param other a predicate that will be logically-ORed with this predicate. - * @return a composed {@code FailableIntPredicate} like - * {@link IntPredicate#and(IntPredicate)}. - * @throws NullPointerException if other is null - */ - default FailableIntPredicate or(final FailableIntPredicate other) { - Objects.requireNonNull(other); - return t -> test(t) || other.test(t); - } - - /** - * Tests the predicate. - * - * @param value the parameter for the predicate to accept. - * @return {@code true} if the input argument matches the predicate, - * {@code false} otherwise. - * @throws E Thrown when the consumer fails. - */ - boolean test(int value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableIntSupplier.java b/sources/main/java/org/apache/commons/lang3/function/FailableIntSupplier.java deleted file mode 100644 index c25af6b9..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableIntSupplier.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.IntSupplier; - -/** - * A functional interface like {@link IntSupplier} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableIntSupplier { - - /** - * Supplies an int. - * - * @return a result - * @throws E if the supplier fails - */ - int getAsInt() throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableIntToDoubleFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableIntToDoubleFunction.java deleted file mode 100644 index 515953a9..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableIntToDoubleFunction.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.IntToDoubleFunction; - -/** - * A functional interface like {@link IntToDoubleFunction} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableIntToDoubleFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableIntToDoubleFunction NOP = t -> 0d; - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableIntToDoubleFunction nop() { - return NOP; - } - - /** - * Applies this function to the given argument. - * - * @param value the function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - double applyAsDouble(int value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableIntToLongFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableIntToLongFunction.java deleted file mode 100644 index d04bebea..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableIntToLongFunction.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.IntToLongFunction; - -/** - * A functional interface like {@link IntToLongFunction} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableIntToLongFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableIntToLongFunction NOP = t -> 0L; - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableIntToLongFunction nop() { - return NOP; - } - - /** - * Applies this function to the given argument. - * - * @param value the function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - long applyAsLong(int value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableIntUnaryOperator.java b/sources/main/java/org/apache/commons/lang3/function/FailableIntUnaryOperator.java deleted file mode 100644 index 19168fe6..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableIntUnaryOperator.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.IntUnaryOperator; - -/** - * A functional interface like {@link IntUnaryOperator} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -public interface FailableIntUnaryOperator { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableIntUnaryOperator NOP = t -> 0; - - /** - * Returns a unary operator that always returns its input argument. - * - * @param Thrown exception. - * @return a unary operator that always returns its input argument - */ - static FailableIntUnaryOperator identity() { - return t -> t; - } - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableIntUnaryOperator nop() { - return NOP; - } - - /** - * Returns a composed {@code FailableDoubleUnaryOperator} like - * {@link IntUnaryOperator#andThen(IntUnaryOperator)}. - * - * @param after the operator to apply after this one. - * @return a composed {@code FailableIntUnaryOperator} like - * {@link IntUnaryOperator#andThen(IntUnaryOperator)}. - * @throws NullPointerException if after is null. - * @see #compose(FailableIntUnaryOperator) - */ - default FailableIntUnaryOperator andThen(final FailableIntUnaryOperator after) { - Objects.requireNonNull(after); - return (final int t) -> after.applyAsInt(applyAsInt(t)); - } - - /** - * Applies this operator to the given operand. - * - * @param operand the operand - * @return the operator result - * @throws E Thrown when a consumer fails. - */ - int applyAsInt(int operand) throws E; - - /** - * Returns a composed {@code FailableIntUnaryOperator} like - * {@link IntUnaryOperator#compose(IntUnaryOperator)}. - * - * @param before the operator to apply before this one. - * @return a composed {@code FailableIntUnaryOperator} like - * {@link IntUnaryOperator#compose(IntUnaryOperator)}. - * @throws NullPointerException if before is null. - * @see #andThen(FailableIntUnaryOperator) - */ - default FailableIntUnaryOperator compose(final FailableIntUnaryOperator before) { - Objects.requireNonNull(before); - return (final int v) -> applyAsInt(before.applyAsInt(v)); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableLongBinaryOperator.java b/sources/main/java/org/apache/commons/lang3/function/FailableLongBinaryOperator.java deleted file mode 100644 index b258f491..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableLongBinaryOperator.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.LongBinaryOperator; - -/** - * A functional interface like {@link LongBinaryOperator} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableLongBinaryOperator { - - /** - * Applies this operator to the given operands. - * - * @param left the first operand - * @param right the second operand - * @return the operator result - * @throws E if the operation fails - */ - long applyAsLong(long left, long right) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableLongConsumer.java b/sources/main/java/org/apache/commons/lang3/function/FailableLongConsumer.java deleted file mode 100644 index eab50cdf..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableLongConsumer.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.LongConsumer; - -/** - * A functional interface like {@link LongConsumer} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableLongConsumer { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableLongConsumer NOP = t -> { - /* NOP */}; - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableLongConsumer nop() { - return NOP; - } - - /** - * Accepts the consumer. - * - * @param object the parameter for the consumable to accept - * @throws E Thrown when the consumer fails. - */ - void accept(long object) throws E; - - /** - * Returns a composed {@code FailableLongConsumer} like - * {@link LongConsumer#andThen(LongConsumer)}. - * - * @param after the operation to perform after this one. - * @return a composed {@code FailableLongConsumer} like - * {@link LongConsumer#andThen(LongConsumer)}. - * @throws NullPointerException if {@code after} is null - */ - default FailableLongConsumer andThen(final FailableLongConsumer after) { - Objects.requireNonNull(after); - return (final long t) -> { - accept(t); - after.accept(t); - }; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableLongFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableLongFunction.java deleted file mode 100644 index c38da09c..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableLongFunction.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.LongFunction; - -/** - * A functional interface like {@link LongFunction} that declares a - * {@code Throwable}. - * - * @param Return type. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableLongFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableLongFunction NOP = t -> null; - - /** - * Returns The NOP singleton. - * - * @param Return type. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableLongFunction nop() { - return NOP; - } - - /** - * Applies this function. - * - * @param input the input for the function - * @return the result of the function - * @throws E Thrown when the function fails. - */ - R apply(long input) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableLongPredicate.java b/sources/main/java/org/apache/commons/lang3/function/FailableLongPredicate.java deleted file mode 100644 index 46a4d834..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableLongPredicate.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.LongPredicate; - -/** - * A functional interface like {@link LongPredicate} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableLongPredicate { - - /** FALSE singleton */ - @SuppressWarnings("rawtypes") - FailableLongPredicate FALSE = t -> false; - - /** TRUE singleton */ - @SuppressWarnings("rawtypes") - FailableLongPredicate TRUE = t -> true; - - /** - * Returns The FALSE singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableLongPredicate falsePredicate() { - return FALSE; - } - - /** - * Returns The FALSE TRUE. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableLongPredicate truePredicate() { - return TRUE; - } - - /** - * Returns a composed {@code FailableLongPredicate} like - * {@link LongPredicate#and(LongPredicate)}. - * - * @param other a predicate that will be logically-ANDed with this predicate. - * @return a composed {@code FailableLongPredicate} like - * {@link LongPredicate#and(LongPredicate)}. - * @throws NullPointerException if other is null - */ - default FailableLongPredicate and(final FailableLongPredicate other) { - Objects.requireNonNull(other); - return t -> test(t) && other.test(t); - } - - /** - * Returns a predicate that negates this predicate. - * - * @return a predicate that negates this predicate. - */ - default FailableLongPredicate negate() { - return t -> !test(t); - } - - /** - * Returns a composed {@code FailableLongPredicate} like - * {@link LongPredicate#and(LongPredicate)}. - * - * @param other a predicate that will be logically-ORed with this predicate. - * @return a composed {@code FailableLongPredicate} like - * {@link LongPredicate#and(LongPredicate)}. - * @throws NullPointerException if other is null - */ - default FailableLongPredicate or(final FailableLongPredicate other) { - Objects.requireNonNull(other); - return t -> test(t) || other.test(t); - } - - /** - * Tests the predicate. - * - * @param value the parameter for the predicate to accept. - * @return {@code true} if the input argument matches the predicate, - * {@code false} otherwise. - * @throws E Thrown when the consumer fails. - */ - boolean test(long value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableLongSupplier.java b/sources/main/java/org/apache/commons/lang3/function/FailableLongSupplier.java deleted file mode 100644 index 1d732573..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableLongSupplier.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.LongSupplier; - -/** - * A functional interface like {@link LongSupplier} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableLongSupplier { - - /** - * Supplies a long. - * - * @return a result - * @throws E if the supplier fails - */ - long getAsLong() throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableLongToDoubleFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableLongToDoubleFunction.java deleted file mode 100644 index 5c49c123..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableLongToDoubleFunction.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.LongToDoubleFunction; - -/** - * A functional interface like {@link LongToDoubleFunction} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableLongToDoubleFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableLongToDoubleFunction NOP = t -> 0d; - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableLongToDoubleFunction nop() { - return NOP; - } - - /** - * Applies this function to the given argument. - * - * @param value the function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - double applyAsDouble(long value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableLongToIntFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableLongToIntFunction.java deleted file mode 100644 index dcd52966..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableLongToIntFunction.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.LongToIntFunction; - -/** - * A functional interface like {@link LongToIntFunction} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableLongToIntFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableLongToIntFunction NOP = t -> 0; - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableLongToIntFunction nop() { - return NOP; - } - - /** - * Applies this function to the given argument. - * - * @param value the function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - int applyAsInt(long value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableLongUnaryOperator.java b/sources/main/java/org/apache/commons/lang3/function/FailableLongUnaryOperator.java deleted file mode 100644 index 43ef034f..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableLongUnaryOperator.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.LongUnaryOperator; - -/** - * A functional interface like {@link LongUnaryOperator} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -public interface FailableLongUnaryOperator { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableLongUnaryOperator NOP = t -> 0L; - - /** - * Returns a unary operator that always returns its input argument. - * - * @param Thrown exception. - * @return a unary operator that always returns its input argument - */ - static FailableLongUnaryOperator identity() { - return t -> t; - } - - /** - * Returns The NOP singleton. - * - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableLongUnaryOperator nop() { - return NOP; - } - - /** - * Returns a composed {@code FailableDoubleUnaryOperator} like - * {@link LongUnaryOperator#andThen(LongUnaryOperator)}. - * - * @param after the operator to apply after this one. - * @return a composed {@code FailableLongUnaryOperator} like - * {@link LongUnaryOperator#andThen(LongUnaryOperator)}. - * @throws NullPointerException if after is null. - * @see #compose(FailableLongUnaryOperator) - */ - default FailableLongUnaryOperator andThen(final FailableLongUnaryOperator after) { - Objects.requireNonNull(after); - return (final long t) -> after.applyAsLong(applyAsLong(t)); - } - - /** - * Applies this operator to the given operand. - * - * @param operand the operand - * @return the operator result - * @throws E Thrown when a consumer fails. - */ - long applyAsLong(long operand) throws E; - - /** - * Returns a composed {@code FailableLongUnaryOperator} like - * {@link LongUnaryOperator#compose(LongUnaryOperator)}. - * - * @param before the operator to apply before this one. - * @return a composed {@code FailableLongUnaryOperator} like - * {@link LongUnaryOperator#compose(LongUnaryOperator)}. - * @throws NullPointerException if before is null. - * @see #andThen(FailableLongUnaryOperator) - */ - default FailableLongUnaryOperator compose(final FailableLongUnaryOperator before) { - Objects.requireNonNull(before); - return (final long v) -> applyAsLong(before.applyAsLong(v)); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableObjDoubleConsumer.java b/sources/main/java/org/apache/commons/lang3/function/FailableObjDoubleConsumer.java deleted file mode 100644 index 1cdddf32..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableObjDoubleConsumer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.ObjDoubleConsumer; - -/** - * A functional interface like {@link ObjDoubleConsumer} that declares a - * {@code Throwable}. - * - * @param the type of the object argument to the operation. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableObjDoubleConsumer { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableObjDoubleConsumer NOP = (t, u) -> { - /* NOP */}; - - /** - * Returns The NOP singleton. - * - * @param the type of the object argument to the operation. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableObjDoubleConsumer nop() { - return NOP; - } - - /** - * Accepts the consumer. - * - * @param object the object parameter for the consumable to accept. - * @param value the double parameter for the consumable to accept. - * @throws E Thrown when the consumer fails. - */ - void accept(T object, double value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableObjIntConsumer.java b/sources/main/java/org/apache/commons/lang3/function/FailableObjIntConsumer.java deleted file mode 100644 index 3620c517..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableObjIntConsumer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.ObjIntConsumer; - -/** - * A functional interface like {@link ObjIntConsumer} that declares a - * {@code Throwable}. - * - * @param the type of the object argument to the operation. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableObjIntConsumer { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableObjIntConsumer NOP = (t, u) -> { - /* NOP */}; - - /** - * Returns The NOP singleton. - * - * @param the type of the object argument to the operation. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableObjIntConsumer nop() { - return NOP; - } - - /** - * Accepts the consumer. - * - * @param object the object parameter for the consumable to accept. - * @param value the int parameter for the consumable to accept. - * @throws E Thrown when the consumer fails. - */ - void accept(T object, int value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableObjLongConsumer.java b/sources/main/java/org/apache/commons/lang3/function/FailableObjLongConsumer.java deleted file mode 100644 index 997a531b..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableObjLongConsumer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.ObjLongConsumer; - -/** - * A functional interface like {@link ObjLongConsumer} that declares a - * {@code Throwable}. - * - * @param the type of the object argument to the operation. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableObjLongConsumer { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableObjLongConsumer NOP = (t, u) -> { - /* NOP */}; - - /** - * Returns The NOP singleton. - * - * @param the type of the object argument to the operation. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableObjLongConsumer nop() { - return NOP; - } - - /** - * Accepts the consumer. - * - * @param object the object parameter for the consumable to accept. - * @param value the long parameter for the consumable to accept. - * @throws E Thrown when the consumer fails. - */ - void accept(T object, long value) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailablePredicate.java b/sources/main/java/org/apache/commons/lang3/function/FailablePredicate.java deleted file mode 100644 index 62f90e59..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailablePredicate.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.Predicate; - -/** - * A functional interface like {@link Predicate} that declares a - * {@code Throwable}. - * - * @param Predicate type. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailablePredicate { - - /** FALSE singleton */ - @SuppressWarnings("rawtypes") - FailablePredicate FALSE = t -> false; - - /** TRUE singleton */ - @SuppressWarnings("rawtypes") - FailablePredicate TRUE = t -> true; - - /** - * Returns The FALSE singleton. - * - * @param Predicate type. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailablePredicate falsePredicate() { - return FALSE; - } - - /** - * Returns The FALSE TRUE. - * - * @param Predicate type. - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailablePredicate truePredicate() { - return TRUE; - } - - /** - * Returns a composed {@code FailablePredicate} like - * {@link Predicate#and(Predicate)}. - * - * @param other a predicate that will be logically-ANDed with this predicate. - * @return a composed {@code FailablePredicate} like - * {@link Predicate#and(Predicate)}. - * @throws NullPointerException if other is null - */ - default FailablePredicate and(final FailablePredicate other) { - Objects.requireNonNull(other); - return t -> test(t) && other.test(t); - } - - /** - * Returns a predicate that negates this predicate. - * - * @return a predicate that negates this predicate. - */ - default FailablePredicate negate() { - return t -> !test(t); - } - - /** - * Returns a composed {@code FailablePredicate} like - * {@link Predicate#and(Predicate)}. - * - * @param other a predicate that will be logically-ORed with this predicate. - * @return a composed {@code FailablePredicate} like - * {@link Predicate#and(Predicate)}. - * @throws NullPointerException if other is null - */ - default FailablePredicate or(final FailablePredicate other) { - Objects.requireNonNull(other); - return t -> test(t) || other.test(t); - } - - /** - * Tests the predicate. - * - * @param object the object to test the predicate on - * @return the predicate's evaluation - * @throws E if the predicate fails - */ - boolean test(T object) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableRunnable.java b/sources/main/java/org/apache/commons/lang3/function/FailableRunnable.java deleted file mode 100644 index 5e76d4c1..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableRunnable.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -/** - * A functional interface like {@link Runnable} that declares a - * {@code Throwable}. - * - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableRunnable { - - /** - * Runs the function. - * - * @throws E Thrown when the function fails. - */ - void run() throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableShortSupplier.java b/sources/main/java/org/apache/commons/lang3/function/FailableShortSupplier.java deleted file mode 100644 index 95400b89..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableShortSupplier.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.IntSupplier; - -/** - * A functional interface like {@link IntSupplier} but for {@code short} that - * declares a {@code Throwable}. - * - * @param Thrown exception. - * @since 3.12.0 - */ -@FunctionalInterface -public interface FailableShortSupplier { - - /** - * Supplies an int. - * - * @return a result - * @throws E if the supplier fails - */ - short getAsShort() throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableSupplier.java b/sources/main/java/org/apache/commons/lang3/function/FailableSupplier.java deleted file mode 100644 index a9b03edc..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableSupplier.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.Supplier; - -/** - * A functional interface like {@link Supplier} that declares a - * {@code Throwable}. - * - * @param Return type. - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableSupplier { - - /** - * Supplies an object - * - * @return a result - * @throws E if the supplier fails - */ - R get() throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableToDoubleBiFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableToDoubleBiFunction.java deleted file mode 100644 index 2246e035..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableToDoubleBiFunction.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.ToDoubleBiFunction; - -/** - * A functional interface like {@link ToDoubleBiFunction} that declares a - * {@code Throwable}. - * - * @param the type of the first argument to the function - * @param the type of the second argument to the function - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableToDoubleBiFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableToDoubleBiFunction NOP = (t, u) -> 0d; - - /** - * Returns The NOP singleton. - * - * @param the type of the first argument to the function - * @param the type of the second argument to the function - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableToDoubleBiFunction nop() { - return NOP; - } - - /** - * Applies this function to the given arguments. - * - * @param t the first function argument - * @param u the second function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - double applyAsDouble(T t, U u) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableToDoubleFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableToDoubleFunction.java deleted file mode 100644 index 85baa016..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableToDoubleFunction.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.ToDoubleFunction; - -/** - * A functional interface like {@link ToDoubleFunction} that declares a - * {@code Throwable}. - * - * @param the type of the argument to the function - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableToDoubleFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableToDoubleFunction NOP = t -> 0d; - - /** - * Returns The NOP singleton. - * - * @param the type of the argument to the function - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableToDoubleFunction nop() { - return NOP; - } - - /** - * Applies this function to the given arguments. - * - * @param t the first function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - double applyAsDouble(T t) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableToIntBiFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableToIntBiFunction.java deleted file mode 100644 index 819cef78..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableToIntBiFunction.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.ToIntBiFunction; - -/** - * A functional interface like {@link ToIntBiFunction} that declares a - * {@code Throwable}. - * - * @param the type of the first argument to the function - * @param the type of the second argument to the function - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableToIntBiFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableToIntBiFunction NOP = (t, u) -> 0; - - /** - * Returns The NOP singleton. - * - * @param the type of the first argument to the function - * @param the type of the second argument to the function - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableToIntBiFunction nop() { - return NOP; - } - - /** - * Applies this function to the given arguments. - * - * @param t the first function argument - * @param u the second function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - int applyAsInt(T t, U u) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableToIntFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableToIntFunction.java deleted file mode 100644 index cb353d23..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableToIntFunction.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.ToIntFunction; - -/** - * A functional interface like {@link ToIntFunction} that declares a - * {@code Throwable}. - * - * @param the type of the argument to the function - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableToIntFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableToIntFunction NOP = t -> 0; - - /** - * Returns The NOP singleton. - * - * @param the type of the argument to the function - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableToIntFunction nop() { - return NOP; - } - - /** - * Applies this function to the given arguments. - * - * @param t the first function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - int applyAsInt(T t) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableToLongBiFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableToLongBiFunction.java deleted file mode 100644 index cbc0cbcc..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableToLongBiFunction.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.ToLongBiFunction; - -/** - * A functional interface like {@link ToLongBiFunction} that declares a - * {@code Throwable}. - * - * @param the type of the first argument to the function - * @param the type of the second argument to the function - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableToLongBiFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableToLongBiFunction NOP = (t, u) -> 0; - - /** - * Returns The NOP singleton. - * - * @param the type of the first argument to the function - * @param the type of the second argument to the function - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableToLongBiFunction nop() { - return NOP; - } - - /** - * Applies this function to the given arguments. - * - * @param t the first function argument - * @param u the second function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - long applyAsLong(T t, U u) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/FailableToLongFunction.java b/sources/main/java/org/apache/commons/lang3/function/FailableToLongFunction.java deleted file mode 100644 index b51500ab..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/FailableToLongFunction.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.ToLongFunction; - -/** - * A functional interface like {@link ToLongFunction} that declares a - * {@code Throwable}. - * - * @param the type of the first argument to the function - * @param Thrown exception. - * @since 3.11 - */ -@FunctionalInterface -public interface FailableToLongFunction { - - /** NOP singleton */ - @SuppressWarnings("rawtypes") - FailableToLongFunction NOP = t -> 0L; - - /** - * Returns The NOP singleton. - * - * @param the type of the argument to the function - * @param Thrown exception. - * @return The NOP singleton. - */ - static FailableToLongFunction nop() { - return NOP; - } - - /** - * Applies this function to the given arguments. - * - * @param t the first function argument - * @return the function result - * @throws E Thrown when the function fails. - */ - long applyAsLong(T t) throws E; -} diff --git a/sources/main/java/org/apache/commons/lang3/function/ToBooleanBiFunction.java b/sources/main/java/org/apache/commons/lang3/function/ToBooleanBiFunction.java deleted file mode 100644 index bfcedb2f..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/ToBooleanBiFunction.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.function; - -import java.util.function.BiFunction; - -/** - * A function that accepts two arguments and produces a boolean result. This is - * the {@code boolean}-producing primitive specialization for - * {@link BiFunction}. - * - * @param the type of the first argument to the function. - * @param the type of the second argument to the function. - * - * @see BiFunction - * @since 3.12.0 - */ -@FunctionalInterface -public interface ToBooleanBiFunction { - - /** - * Applies this function to the given arguments. - * - * @param t the first function argument. - * @param u the second function argument. - * @return the function result. - */ - boolean applyAsBoolean(T t, U u); -} diff --git a/sources/main/java/org/apache/commons/lang3/function/TriFunction.java b/sources/main/java/org/apache/commons/lang3/function/TriFunction.java deleted file mode 100644 index 45c34706..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/TriFunction.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.function; - -import java.util.Objects; -import java.util.function.Function; - -/** - * Represents a function that accepts three arguments and produces a result. - * This is the three-arity specialization of {@link Function}. - * - *

- * This is a functional interface whose - * functional method is {@link #apply(Object, Object, Object)}. - *

- * - * @param the type of the first argument to the function - * @param the type of the second argument to the function - * @param the type of the third argument to the function - * @param the type of the result of the function - * - * @see Function - * @since 3.12.0 - */ -@FunctionalInterface -public interface TriFunction { - - /** - * Applies this function to the given arguments. - * - * @param t the first function argument - * @param u the second function argument - * @param v the third function argument - * @return the function result - */ - R apply(T t, U u, V v); - - /** - * Returns a composed function that first applies this function to its input, - * and then applies the {@code after} function to the result. If evaluation of - * either function throws an exception, it is relayed to the caller of the - * composed function. - * - * @param the type of output of the {@code after} function, and of the - * composed function - * @param after the function to apply after this function is applied - * @return a composed function that first applies this function and then applies - * the {@code after} function - * @throws NullPointerException if after is null - */ - default TriFunction andThen(final Function after) { - Objects.requireNonNull(after); - return (final T t, final U u, final V v) -> after.apply(apply(t, u, v)); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/function/package-info.java b/sources/main/java/org/apache/commons/lang3/function/package-info.java deleted file mode 100644 index 0f55a71b..00000000 --- a/sources/main/java/org/apache/commons/lang3/function/package-info.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Provides functional interfaces to complement those in - * {@code java.lang.function} and utilities for working with Java 8 lambdas. - * - *

- * Contains failable functional interfaces that address the fact that lambdas - * are supposed not to throw Exceptions, at least not checked Exceptions, A.K.A. - * instances of {@link java.lang.Exception}. A failable functional interface - * declares a type of Exception that may be raised if the function fails. - *

- * - * @since 3.11 - */ -package org.apache.commons.lang3.function; diff --git a/sources/main/java/org/apache/commons/lang3/math/Fraction.java b/sources/main/java/org/apache/commons/lang3/math/Fraction.java deleted file mode 100644 index f40bdb72..00000000 --- a/sources/main/java/org/apache/commons/lang3/math/Fraction.java +++ /dev/null @@ -1,1025 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.math; - -import java.math.BigInteger; - -import org.apache.commons.lang3.Validate; - -/** - *

- * {@code Fraction} is a {@code Number} implementation that stores fractions - * accurately. - *

- * - *

- * This class is immutable, and interoperable with most methods that accept a - * {@code Number}. - *

- * - *

- * Note that this class is intended for common use cases, it is int based - * and thus suffers from various overflow issues. For a BigInteger based - * equivalent, please see the Commons Math BigFraction class. - *

- * - * @since 2.0 - */ -public final class Fraction extends Number implements Comparable { - - /** - * Required for serialization support. Lang version 2.0. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 65382027393090L; - - /** - * {@code Fraction} representation of 0. - */ - public static final Fraction ZERO = new Fraction(0, 1); - /** - * {@code Fraction} representation of 1. - */ - public static final Fraction ONE = new Fraction(1, 1); - /** - * {@code Fraction} representation of 1/2. - */ - public static final Fraction ONE_HALF = new Fraction(1, 2); - /** - * {@code Fraction} representation of 1/3. - */ - public static final Fraction ONE_THIRD = new Fraction(1, 3); - /** - * {@code Fraction} representation of 2/3. - */ - public static final Fraction TWO_THIRDS = new Fraction(2, 3); - /** - * {@code Fraction} representation of 1/4. - */ - public static final Fraction ONE_QUARTER = new Fraction(1, 4); - /** - * {@code Fraction} representation of 2/4. - */ - public static final Fraction TWO_QUARTERS = new Fraction(2, 4); - /** - * {@code Fraction} representation of 3/4. - */ - public static final Fraction THREE_QUARTERS = new Fraction(3, 4); - /** - * {@code Fraction} representation of 1/5. - */ - public static final Fraction ONE_FIFTH = new Fraction(1, 5); - /** - * {@code Fraction} representation of 2/5. - */ - public static final Fraction TWO_FIFTHS = new Fraction(2, 5); - /** - * {@code Fraction} representation of 3/5. - */ - public static final Fraction THREE_FIFTHS = new Fraction(3, 5); - /** - * {@code Fraction} representation of 4/5. - */ - public static final Fraction FOUR_FIFTHS = new Fraction(4, 5); - - /** - * The numerator number part of the fraction (the three in three sevenths). - */ - private final int numerator; - /** - * The denominator number part of the fraction (the seven in three sevenths). - */ - private final int denominator; - - /** - * Cached output hashCode (class is immutable). - */ - private transient int hashCode; - /** - * Cached output toString (class is immutable). - */ - private transient String toString; - /** - * Cached output toProperString (class is immutable). - */ - private transient String toProperString; - - /** - *

- * Constructs a {@code Fraction} instance with the 2 parts of a fraction Y/Z. - *

- * - * @param numerator the numerator, for example the three in 'three sevenths' - * @param denominator the denominator, for example the seven in 'three sevenths' - */ - private Fraction(final int numerator, final int denominator) { - this.numerator = numerator; - this.denominator = denominator; - } - - /** - *

- * Creates a {@code Fraction} instance with the 2 parts of a fraction Y/Z. - *

- * - *

- * Any negative signs are resolved to be on the numerator. - *

- * - * @param numerator the numerator, for example the three in 'three sevenths' - * @param denominator the denominator, for example the seven in 'three sevenths' - * @return a new fraction instance - * @throws ArithmeticException if the denominator is {@code zero} or the - * denominator is {@code negative} and the numerator - * is {@code Integer#MIN_VALUE} - */ - public static Fraction getFraction(int numerator, int denominator) { - if (denominator == 0) { - throw new ArithmeticException("The denominator must not be zero"); - } - if (denominator < 0) { - if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) { - throw new ArithmeticException("overflow: can't negate"); - } - numerator = -numerator; - denominator = -denominator; - } - return new Fraction(numerator, denominator); - } - - /** - *

- * Creates a {@code Fraction} instance with the 3 parts of a fraction X Y/Z. - *

- * - *

- * The negative sign must be passed in on the whole number part. - *

- * - * @param whole the whole number, for example the one in 'one and three - * sevenths' - * @param numerator the numerator, for example the three in 'one and three - * sevenths' - * @param denominator the denominator, for example the seven in 'one and three - * sevenths' - * @return a new fraction instance - * @throws ArithmeticException if the denominator is {@code zero} - * @throws ArithmeticException if the denominator is negative - * @throws ArithmeticException if the numerator is negative - * @throws ArithmeticException if the resulting numerator exceeds - * {@code Integer.MAX_VALUE} - */ - public static Fraction getFraction(final int whole, final int numerator, final int denominator) { - if (denominator == 0) { - throw new ArithmeticException("The denominator must not be zero"); - } - if (denominator < 0) { - throw new ArithmeticException("The denominator must not be negative"); - } - if (numerator < 0) { - throw new ArithmeticException("The numerator must not be negative"); - } - final long numeratorValue; - if (whole < 0) { - numeratorValue = whole * (long) denominator - numerator; - } else { - numeratorValue = whole * (long) denominator + numerator; - } - if (numeratorValue < Integer.MIN_VALUE || numeratorValue > Integer.MAX_VALUE) { - throw new ArithmeticException("Numerator too large to represent as an Integer."); - } - return new Fraction((int) numeratorValue, denominator); - } - - /** - *

- * Creates a reduced {@code Fraction} instance with the 2 parts of a fraction - * Y/Z. - *

- * - *

- * For example, if the input parameters represent 2/4, then the created fraction - * will be 1/2. - *

- * - *

- * Any negative signs are resolved to be on the numerator. - *

- * - * @param numerator the numerator, for example the three in 'three sevenths' - * @param denominator the denominator, for example the seven in 'three sevenths' - * @return a new fraction instance, with the numerator and denominator reduced - * @throws ArithmeticException if the denominator is {@code zero} - */ - public static Fraction getReducedFraction(int numerator, int denominator) { - if (denominator == 0) { - throw new ArithmeticException("The denominator must not be zero"); - } - if (numerator == 0) { - return ZERO; // normalize zero. - } - // allow 2^k/-2^31 as a valid fraction (where k>0) - if (denominator == Integer.MIN_VALUE && (numerator & 1) == 0) { - numerator /= 2; - denominator /= 2; - } - if (denominator < 0) { - if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) { - throw new ArithmeticException("overflow: can't negate"); - } - numerator = -numerator; - denominator = -denominator; - } - // simplify fraction. - final int gcd = greatestCommonDivisor(numerator, denominator); - numerator /= gcd; - denominator /= gcd; - return new Fraction(numerator, denominator); - } - - /** - *

- * Creates a {@code Fraction} instance from a {@code double} value. - *

- * - *

- * This method uses the - * continued - * fraction algorithm, computing a maximum of 25 convergents and bounding - * the denominator by 10,000. - *

- * - * @param value the double value to convert - * @return a new fraction instance that is close to the value - * @throws ArithmeticException if {@code |value| > Integer.MAX_VALUE} or - * {@code value = NaN} - * @throws ArithmeticException if the calculated denominator is {@code zero} - * @throws ArithmeticException if the algorithm does not converge - */ - public static Fraction getFraction(double value) { - final int sign = value < 0 ? -1 : 1; - value = Math.abs(value); - if (value > Integer.MAX_VALUE || Double.isNaN(value)) { - throw new ArithmeticException("The value must not be greater than Integer.MAX_VALUE or NaN"); - } - final int wholeNumber = (int) value; - value -= wholeNumber; - - int numer0 = 0; // the pre-previous - int denom0 = 1; // the pre-previous - int numer1 = 1; // the previous - int denom1 = 0; // the previous - int numer2 = 0; // the current, setup in calculation - int denom2 = 0; // the current, setup in calculation - int a1 = (int) value; - int a2 = 0; - double x1 = 1; - double x2 = 0; - double y1 = value - a1; - double y2 = 0; - double delta1, delta2 = Double.MAX_VALUE; - double fraction; - int i = 1; - do { - delta1 = delta2; - a2 = (int) (x1 / y1); - x2 = y1; - y2 = x1 - a2 * y1; - numer2 = a1 * numer1 + numer0; - denom2 = a1 * denom1 + denom0; - fraction = (double) numer2 / (double) denom2; - delta2 = Math.abs(value - fraction); - a1 = a2; - x1 = x2; - y1 = y2; - numer0 = numer1; - denom0 = denom1; - numer1 = numer2; - denom1 = denom2; - i++; - } while (delta1 > delta2 && denom2 <= 10000 && denom2 > 0 && i < 25); - if (i == 25) { - throw new ArithmeticException("Unable to convert double to fraction"); - } - return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0); - } - - /** - *

- * Creates a Fraction from a {@code String}. - *

- * - *

- * The formats accepted are: - *

- * - *
    - *
  1. {@code double} String containing a dot
  2. - *
  3. 'X Y/Z'
  4. - *
  5. 'Y/Z'
  6. - *
  7. 'X' (a simple whole number)
  8. - *
- *

- * and a . - *

- * - * @param str the string to parse, must not be {@code null} - * @return the new {@code Fraction} instance - * @throws NullPointerException if the string is {@code null} - * @throws NumberFormatException if the number format is invalid - */ - public static Fraction getFraction(String str) { - Validate.notNull(str, "str"); - // parse double format - int pos = str.indexOf('.'); - if (pos >= 0) { - return getFraction(Double.parseDouble(str)); - } - - // parse X Y/Z format - pos = str.indexOf(' '); - if (pos > 0) { - final int whole = Integer.parseInt(str.substring(0, pos)); - str = str.substring(pos + 1); - pos = str.indexOf('/'); - if (pos < 0) { - throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z"); - } - final int numer = Integer.parseInt(str.substring(0, pos)); - final int denom = Integer.parseInt(str.substring(pos + 1)); - return getFraction(whole, numer, denom); - } - - // parse Y/Z format - pos = str.indexOf('/'); - if (pos < 0) { - // simple whole number - return getFraction(Integer.parseInt(str), 1); - } - final int numer = Integer.parseInt(str.substring(0, pos)); - final int denom = Integer.parseInt(str.substring(pos + 1)); - return getFraction(numer, denom); - } - - // Accessors - // ------------------------------------------------------------------- - - /** - *

- * Gets the numerator part of the fraction. - *

- * - *

- * This method may return a value greater than the denominator, an improper - * fraction, such as the seven in 7/4. - *

- * - * @return the numerator fraction part - */ - public int getNumerator() { - return numerator; - } - - /** - *

- * Gets the denominator part of the fraction. - *

- * - * @return the denominator fraction part - */ - public int getDenominator() { - return denominator; - } - - /** - *

- * Gets the proper numerator, always positive. - *

- * - *

- * An improper fraction 7/4 can be resolved into a proper one, 1 3/4. This - * method returns the 3 from the proper fraction. - *

- * - *

- * If the fraction is negative such as -7/4, it can be resolved into -1 3/4, so - * this method returns the positive proper numerator, 3. - *

- * - * @return the numerator fraction part of a proper fraction, always positive - */ - public int getProperNumerator() { - return Math.abs(numerator % denominator); - } - - /** - *

- * Gets the proper whole part of the fraction. - *

- * - *

- * An improper fraction 7/4 can be resolved into a proper one, 1 3/4. This - * method returns the 1 from the proper fraction. - *

- * - *

- * If the fraction is negative such as -7/4, it can be resolved into -1 3/4, so - * this method returns the positive whole part -1. - *

- * - * @return the whole fraction part of a proper fraction, that includes the sign - */ - public int getProperWhole() { - return numerator / denominator; - } - - // Number methods - // ------------------------------------------------------------------- - - /** - *

- * Gets the fraction as an {@code int}. This returns the whole number part of - * the fraction. - *

- * - * @return the whole number fraction part - */ - @Override - public int intValue() { - return numerator / denominator; - } - - /** - *

- * Gets the fraction as a {@code long}. This returns the whole number part of - * the fraction. - *

- * - * @return the whole number fraction part - */ - @Override - public long longValue() { - return (long) numerator / denominator; - } - - /** - *

- * Gets the fraction as a {@code float}. This calculates the fraction as the - * numerator divided by denominator. - *

- * - * @return the fraction as a {@code float} - */ - @Override - public float floatValue() { - return (float) numerator / (float) denominator; - } - - /** - *

- * Gets the fraction as a {@code double}. This calculates the fraction as the - * numerator divided by denominator. - *

- * - * @return the fraction as a {@code double} - */ - @Override - public double doubleValue() { - return (double) numerator / (double) denominator; - } - - // Calculations - // ------------------------------------------------------------------- - - /** - *

- * Reduce the fraction to the smallest values for the numerator and denominator, - * returning the result. - *

- * - *

- * For example, if this fraction represents 2/4, then the result will be 1/2. - *

- * - * @return a new reduced fraction instance, or this if no simplification - * possible - */ - public Fraction reduce() { - if (numerator == 0) { - return equals(ZERO) ? this : ZERO; - } - final int gcd = greatestCommonDivisor(Math.abs(numerator), denominator); - if (gcd == 1) { - return this; - } - return getFraction(numerator / gcd, denominator / gcd); - } - - /** - *

- * Gets a fraction that is the inverse (1/fraction) of this one. - *

- * - *

- * The returned fraction is not reduced. - *

- * - * @return a new fraction instance with the numerator and denominator inverted. - * @throws ArithmeticException if the fraction represents zero. - */ - public Fraction invert() { - if (numerator == 0) { - throw new ArithmeticException("Unable to invert zero."); - } - if (numerator == Integer.MIN_VALUE) { - throw new ArithmeticException("overflow: can't negate numerator"); - } - if (numerator < 0) { - return new Fraction(-denominator, -numerator); - } - return new Fraction(denominator, numerator); - } - - /** - *

- * Gets a fraction that is the negative (-fraction) of this one. - *

- * - *

- * The returned fraction is not reduced. - *

- * - * @return a new fraction instance with the opposite signed numerator - */ - public Fraction negate() { - // the positive range is one smaller than the negative range of an int. - if (numerator == Integer.MIN_VALUE) { - throw new ArithmeticException("overflow: too large to negate"); - } - return new Fraction(-numerator, denominator); - } - - /** - *

- * Gets a fraction that is the positive equivalent of this one. - *

- *

- * More precisely: {@code (fraction >= 0 ? this : -fraction)} - *

- * - *

- * The returned fraction is not reduced. - *

- * - * @return {@code this} if it is positive, or a new positive fraction instance - * with the opposite signed numerator - */ - public Fraction abs() { - if (numerator >= 0) { - return this; - } - return negate(); - } - - /** - *

- * Gets a fraction that is raised to the passed in power. - *

- * - *

- * The returned fraction is in reduced form. - *

- * - * @param power the power to raise the fraction to - * @return {@code this} if the power is one, {@code ONE} if the power is zero - * (even if the fraction equals ZERO) or a new fraction instance raised - * to the appropriate power - * @throws ArithmeticException if the resulting numerator or denominator exceeds - * {@code Integer.MAX_VALUE} - */ - public Fraction pow(final int power) { - if (power == 1) { - return this; - } else if (power == 0) { - return ONE; - } else if (power < 0) { - if (power == Integer.MIN_VALUE) { // MIN_VALUE can't be negated. - return this.invert().pow(2).pow(-(power / 2)); - } - return this.invert().pow(-power); - } else { - final Fraction f = this.multiplyBy(this); - if (power % 2 == 0) { // if even... - return f.pow(power / 2); - } - return f.pow(power / 2).multiplyBy(this); - } - } - - /** - *

- * Gets the greatest common divisor of the absolute value of two numbers, using - * the "binary gcd" method which avoids division and modulo operations. See - * Knuth 4.5.2 algorithm B. This algorithm is due to Josef Stein (1961). - *

- * - * @param u a non-zero number - * @param v a non-zero number - * @return the greatest common divisor, never zero - */ - private static int greatestCommonDivisor(int u, int v) { - // From Commons Math: - if (u == 0 || v == 0) { - if (u == Integer.MIN_VALUE || v == Integer.MIN_VALUE) { - throw new ArithmeticException("overflow: gcd is 2^31"); - } - return Math.abs(u) + Math.abs(v); - } - // if either operand is abs 1, return 1: - if (Math.abs(u) == 1 || Math.abs(v) == 1) { - return 1; - } - // keep u and v negative, as negative integers range down to - // -2^31, while positive numbers can only be as large as 2^31-1 - // (i.e. we can't necessarily negate a negative number without - // overflow) - if (u > 0) { - u = -u; - } // make u negative - if (v > 0) { - v = -v; - } // make v negative - // B1. [Find power of 2] - int k = 0; - while ((u & 1) == 0 && (v & 1) == 0 && k < 31) { // while u and v are both even... - u /= 2; - v /= 2; - k++; // cast out twos. - } - if (k == 31) { - throw new ArithmeticException("overflow: gcd is 2^31"); - } - // B2. Initialize: u and v have been divided by 2^k and at least - // one is odd. - int t = (u & 1) == 1 ? v : -(u / 2)/* B3 */; - // t negative: u was odd, v may be even (t replaces v) - // t positive: u was even, v is odd (t replaces u) - do { - /* assert u<0 && v<0; */ - // B4/B3: cast out twos from t. - while ((t & 1) == 0) { // while t is even.. - t /= 2; // cast out twos - } - // B5 [reset max(u,v)] - if (t > 0) { - u = -t; - } else { - v = t; - } - // B6/B3. at this point both u and v should be odd. - t = (v - u) / 2; - // |u| larger: t positive (replace u) - // |v| larger: t negative (replace v) - } while (t != 0); - return -u * (1 << k); // gcd is u*2^k - } - - // Arithmetic - // ------------------------------------------------------------------- - - /** - * Multiply two integers, checking for overflow. - * - * @param x a factor - * @param y a factor - * @return the product {@code x*y} - * @throws ArithmeticException if the result can not be represented as an int - */ - private static int mulAndCheck(final int x, final int y) { - final long m = (long) x * (long) y; - if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) { - throw new ArithmeticException("overflow: mul"); - } - return (int) m; - } - - /** - * Multiply two non-negative integers, checking for overflow. - * - * @param x a non-negative factor - * @param y a non-negative factor - * @return the product {@code x*y} - * @throws ArithmeticException if the result can not be represented as an int - */ - private static int mulPosAndCheck(final int x, final int y) { - /* assert x>=0 && y>=0; */ - final long m = (long) x * (long) y; - if (m > Integer.MAX_VALUE) { - throw new ArithmeticException("overflow: mulPos"); - } - return (int) m; - } - - /** - * Add two integers, checking for overflow. - * - * @param x an addend - * @param y an addend - * @return the sum {@code x+y} - * @throws ArithmeticException if the result can not be represented as an int - */ - private static int addAndCheck(final int x, final int y) { - final long s = (long) x + (long) y; - if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) { - throw new ArithmeticException("overflow: add"); - } - return (int) s; - } - - /** - * Subtract two integers, checking for overflow. - * - * @param x the minuend - * @param y the subtrahend - * @return the difference {@code x-y} - * @throws ArithmeticException if the result can not be represented as an int - */ - private static int subAndCheck(final int x, final int y) { - final long s = (long) x - (long) y; - if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) { - throw new ArithmeticException("overflow: add"); - } - return (int) s; - } - - /** - *

- * Adds the value of this fraction to another, returning the result in reduced - * form. The algorithm follows Knuth, 4.5.1. - *

- * - * @param fraction the fraction to add, must not be {@code null} - * @return a {@code Fraction} instance with the resulting values - * @throws IllegalArgumentException if the fraction is {@code null} - * @throws ArithmeticException if the resulting numerator or denominator - * exceeds {@code Integer.MAX_VALUE} - */ - public Fraction add(final Fraction fraction) { - return addSub(fraction, true /* add */); - } - - /** - *

- * Subtracts the value of another fraction from the value of this one, returning - * the result in reduced form. - *

- * - * @param fraction the fraction to subtract, must not be {@code null} - * @return a {@code Fraction} instance with the resulting values - * @throws IllegalArgumentException if the fraction is {@code null} - * @throws ArithmeticException if the resulting numerator or denominator - * cannot be represented in an {@code int}. - */ - public Fraction subtract(final Fraction fraction) { - return addSub(fraction, false /* subtract */); - } - - /** - * Implement add and subtract using algorithm described in Knuth 4.5.1. - * - * @param fraction the fraction to subtract, must not be {@code null} - * @param isAdd true to add, false to subtract - * @return a {@code Fraction} instance with the resulting values - * @throws IllegalArgumentException if the fraction is {@code null} - * @throws ArithmeticException if the resulting numerator or denominator - * cannot be represented in an {@code int}. - */ - private Fraction addSub(final Fraction fraction, final boolean isAdd) { - Validate.notNull(fraction, "fraction"); - // zero is identity for addition. - if (numerator == 0) { - return isAdd ? fraction : fraction.negate(); - } - if (fraction.numerator == 0) { - return this; - } - // if denominators are randomly distributed, d1 will be 1 about 61% - // of the time. - final int d1 = greatestCommonDivisor(denominator, fraction.denominator); - if (d1 == 1) { - // result is ( (u*v' +/- u'v) / u'v') - final int uvp = mulAndCheck(numerator, fraction.denominator); - final int upv = mulAndCheck(fraction.numerator, denominator); - return new Fraction(isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv), - mulPosAndCheck(denominator, fraction.denominator)); - } - // the quantity 't' requires 65 bits of precision; see knuth 4.5.1 - // exercise 7. we're going to use a BigInteger. - // t = u(v'/d1) +/- v(u'/d1) - final BigInteger uvp = BigInteger.valueOf(numerator).multiply(BigInteger.valueOf(fraction.denominator / d1)); - final BigInteger upv = BigInteger.valueOf(fraction.numerator).multiply(BigInteger.valueOf(denominator / d1)); - final BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv); - // but d2 doesn't need extra precision because - // d2 = gcd(t,d1) = gcd(t mod d1, d1) - final int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue(); - final int d2 = tmodd1 == 0 ? d1 : greatestCommonDivisor(tmodd1, d1); - - // result is (t/d2) / (u'/d1)(v'/d2) - final BigInteger w = t.divide(BigInteger.valueOf(d2)); - if (w.bitLength() > 31) { - throw new ArithmeticException("overflow: numerator too large after multiply"); - } - return new Fraction(w.intValue(), mulPosAndCheck(denominator / d1, fraction.denominator / d2)); - } - - /** - *

- * Multiplies the value of this fraction by another, returning the result in - * reduced form. - *

- * - * @param fraction the fraction to multiply by, must not be {@code null} - * @return a {@code Fraction} instance with the resulting values - * @throws NullPointerException if the fraction is {@code null} - * @throws ArithmeticException if the resulting numerator or denominator - * exceeds {@code Integer.MAX_VALUE} - */ - public Fraction multiplyBy(final Fraction fraction) { - Validate.notNull(fraction, "fraction"); - if (numerator == 0 || fraction.numerator == 0) { - return ZERO; - } - // knuth 4.5.1 - // make sure we don't overflow unless the result *must* overflow. - final int d1 = greatestCommonDivisor(numerator, fraction.denominator); - final int d2 = greatestCommonDivisor(fraction.numerator, denominator); - return getReducedFraction(mulAndCheck(numerator / d1, fraction.numerator / d2), - mulPosAndCheck(denominator / d2, fraction.denominator / d1)); - } - - /** - *

- * Divide the value of this fraction by another. - *

- * - * @param fraction the fraction to divide by, must not be {@code null} - * @return a {@code Fraction} instance with the resulting values - * @throws NullPointerException if the fraction is {@code null} - * @throws ArithmeticException if the fraction to divide by is zero - * @throws ArithmeticException if the resulting numerator or denominator - * exceeds {@code Integer.MAX_VALUE} - */ - public Fraction divideBy(final Fraction fraction) { - Validate.notNull(fraction, "fraction"); - if (fraction.numerator == 0) { - throw new ArithmeticException("The fraction to divide by must not be zero"); - } - return multiplyBy(fraction.invert()); - } - - // Basics - // ------------------------------------------------------------------- - - /** - *

- * Compares this fraction to another object to test if they are equal. - *

- * . - * - *

- * To be equal, both values must be equal. Thus 2/4 is not equal to 1/2. - *

- * - * @param obj the reference object with which to compare - * @return {@code true} if this object is equal - */ - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof Fraction)) { - return false; - } - final Fraction other = (Fraction) obj; - return getNumerator() == other.getNumerator() && getDenominator() == other.getDenominator(); - } - - /** - *

- * Gets a hashCode for the fraction. - *

- * - * @return a hash code value for this object - */ - @Override - public int hashCode() { - if (hashCode == 0) { - // hash code update should be atomic. - hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator(); - } - return hashCode; - } - - /** - *

- * Compares this object to another based on size. - *

- * - *

- * Note: this class has a natural ordering that is inconsistent with equals, - * because, for example, equals treats 1/2 and 2/4 as different, whereas - * compareTo treats them as equal. - * - * @param other the object to compare to - * @return -1 if this is less, 0 if equal, +1 if greater - * @throws ClassCastException if the object is not a {@code Fraction} - * @throws NullPointerException if the object is {@code null} - */ - @Override - public int compareTo(final Fraction other) { - if (this == other) { - return 0; - } - if (numerator == other.numerator && denominator == other.denominator) { - return 0; - } - - // otherwise see which is less - final long first = (long) numerator * (long) other.denominator; - final long second = (long) other.numerator * (long) denominator; - return Long.compare(first, second); - } - - /** - *

- * Gets the fraction as a {@code String}. - *

- * - *

- * The format used is 'numerator/denominator' always. - * - * @return a {@code String} form of the fraction - */ - @Override - public String toString() { - if (toString == null) { - toString = getNumerator() + "/" + getDenominator(); - } - return toString; - } - - /** - *

- * Gets the fraction as a proper {@code String} in the format X Y/Z. - *

- * - *

- * The format used in 'wholeNumber numerator/denominator'. - * If the whole number is zero it will be omitted. If the numerator is zero, - * only the whole number is returned. - *

- * - * @return a {@code String} form of the fraction - */ - public String toProperString() { - if (toProperString == null) { - if (numerator == 0) { - toProperString = "0"; - } else if (numerator == denominator) { - toProperString = "1"; - } else if (numerator == -1 * denominator) { - toProperString = "-1"; - } else if ((numerator > 0 ? -numerator : numerator) < -denominator) { - // note that we do the magnitude comparison test above with - // NEGATIVE (not positive) numbers, since negative numbers - // have a larger range. otherwise numerator==Integer.MIN_VALUE - // is handled incorrectly. - final int properNumerator = getProperNumerator(); - if (properNumerator == 0) { - toProperString = Integer.toString(getProperWhole()); - } else { - toProperString = getProperWhole() + " " + properNumerator + "/" + getDenominator(); - } - } else { - toProperString = getNumerator() + "/" + getDenominator(); - } - } - return toProperString; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/math/IEEE754rUtils.java b/sources/main/java/org/apache/commons/lang3/math/IEEE754rUtils.java deleted file mode 100644 index cb29cf67..00000000 --- a/sources/main/java/org/apache/commons/lang3/math/IEEE754rUtils.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.math; - -import org.apache.commons.lang3.Validate; - -/** - *

- * Provides IEEE-754r variants of NumberUtils methods. - *

- * - *

- * See: http://en.wikipedia.org/wiki/IEEE_754r - *

- * - * @since 2.4 - */ -public class IEEE754rUtils { - - /** - *

- * Returns the minimum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the minimum value in the array - * @throws NullPointerException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from min(double[]) to min(double...) - */ - public static double min(final double... array) { - Validate.notNull(array, "array"); - Validate.isTrue(array.length != 0, "Array cannot be empty."); - - // Finds and returns min - double min = array[0]; - for (int i = 1; i < array.length; i++) { - min = min(array[i], min); - } - - return min; - } - - /** - *

- * Returns the minimum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the minimum value in the array - * @throws NullPointerException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from min(float[]) to min(float...) - */ - public static float min(final float... array) { - Validate.notNull(array, "array"); - Validate.isTrue(array.length != 0, "Array cannot be empty."); - - // Finds and returns min - float min = array[0]; - for (int i = 1; i < array.length; i++) { - min = min(array[i], min); - } - - return min; - } - - /** - *

- * Gets the minimum of three {@code double} values. - *

- * - *

- * NaN is only returned if all numbers are NaN as per IEEE-754r. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the smallest of the values - */ - public static double min(final double a, final double b, final double c) { - return min(min(a, b), c); - } - - /** - *

- * Gets the minimum of two {@code double} values. - *

- * - *

- * NaN is only returned if all numbers are NaN as per IEEE-754r. - *

- * - * @param a value 1 - * @param b value 2 - * @return the smallest of the values - */ - public static double min(final double a, final double b) { - if (Double.isNaN(a)) { - return b; - } else if (Double.isNaN(b)) { - return a; - } else { - return Math.min(a, b); - } - } - - /** - *

- * Gets the minimum of three {@code float} values. - *

- * - *

- * NaN is only returned if all numbers are NaN as per IEEE-754r. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the smallest of the values - */ - public static float min(final float a, final float b, final float c) { - return min(min(a, b), c); - } - - /** - *

- * Gets the minimum of two {@code float} values. - *

- * - *

- * NaN is only returned if all numbers are NaN as per IEEE-754r. - *

- * - * @param a value 1 - * @param b value 2 - * @return the smallest of the values - */ - public static float min(final float a, final float b) { - if (Float.isNaN(a)) { - return b; - } else if (Float.isNaN(b)) { - return a; - } else { - return Math.min(a, b); - } - } - - /** - *

- * Returns the maximum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the minimum value in the array - * @throws NullPointerException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from max(double[]) to max(double...) - */ - public static double max(final double... array) { - Validate.notNull(array, "array"); - Validate.isTrue(array.length != 0, "Array cannot be empty."); - - // Finds and returns max - double max = array[0]; - for (int j = 1; j < array.length; j++) { - max = max(array[j], max); - } - - return max; - } - - /** - *

- * Returns the maximum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the minimum value in the array - * @throws NullPointerException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from max(float[]) to max(float...) - */ - public static float max(final float... array) { - Validate.notNull(array, "array"); - Validate.isTrue(array.length != 0, "Array cannot be empty."); - - // Finds and returns max - float max = array[0]; - for (int j = 1; j < array.length; j++) { - max = max(array[j], max); - } - - return max; - } - - /** - *

- * Gets the maximum of three {@code double} values. - *

- * - *

- * NaN is only returned if all numbers are NaN as per IEEE-754r. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the largest of the values - */ - public static double max(final double a, final double b, final double c) { - return max(max(a, b), c); - } - - /** - *

- * Gets the maximum of two {@code double} values. - *

- * - *

- * NaN is only returned if all numbers are NaN as per IEEE-754r. - *

- * - * @param a value 1 - * @param b value 2 - * @return the largest of the values - */ - public static double max(final double a, final double b) { - if (Double.isNaN(a)) { - return b; - } else if (Double.isNaN(b)) { - return a; - } else { - return Math.max(a, b); - } - } - - /** - *

- * Gets the maximum of three {@code float} values. - *

- * - *

- * NaN is only returned if all numbers are NaN as per IEEE-754r. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the largest of the values - */ - public static float max(final float a, final float b, final float c) { - return max(max(a, b), c); - } - - /** - *

- * Gets the maximum of two {@code float} values. - *

- * - *

- * NaN is only returned if all numbers are NaN as per IEEE-754r. - *

- * - * @param a value 1 - * @param b value 2 - * @return the largest of the values - */ - public static float max(final float a, final float b) { - if (Float.isNaN(a)) { - return b; - } else if (Float.isNaN(b)) { - return a; - } else { - return Math.max(a, b); - } - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/math/NumberUtils.java b/sources/main/java/org/apache/commons/lang3/math/NumberUtils.java deleted file mode 100644 index 1c49c50d..00000000 --- a/sources/main/java/org/apache/commons/lang3/math/NumberUtils.java +++ /dev/null @@ -1,2027 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.math; - -import java.lang.reflect.Array; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.RoundingMode; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; - -/** - *

- * Provides extra functionality for Java Number classes. - *

- * - * @since 2.0 - */ -public class NumberUtils { - - /** Reusable Long constant for zero. */ - public static final Long LONG_ZERO = Long.valueOf(0L); - /** Reusable Long constant for one. */ - public static final Long LONG_ONE = Long.valueOf(1L); - /** Reusable Long constant for minus one. */ - public static final Long LONG_MINUS_ONE = Long.valueOf(-1L); - /** Reusable Integer constant for zero. */ - public static final Integer INTEGER_ZERO = Integer.valueOf(0); - /** Reusable Integer constant for one. */ - public static final Integer INTEGER_ONE = Integer.valueOf(1); - /** Reusable Integer constant for two */ - public static final Integer INTEGER_TWO = Integer.valueOf(2); - /** Reusable Integer constant for minus one. */ - public static final Integer INTEGER_MINUS_ONE = Integer.valueOf(-1); - /** Reusable Short constant for zero. */ - public static final Short SHORT_ZERO = Short.valueOf((short) 0); - /** Reusable Short constant for one. */ - public static final Short SHORT_ONE = Short.valueOf((short) 1); - /** Reusable Short constant for minus one. */ - public static final Short SHORT_MINUS_ONE = Short.valueOf((short) -1); - /** Reusable Byte constant for zero. */ - public static final Byte BYTE_ZERO = Byte.valueOf((byte) 0); - /** Reusable Byte constant for one. */ - public static final Byte BYTE_ONE = Byte.valueOf((byte) 1); - /** Reusable Byte constant for minus one. */ - public static final Byte BYTE_MINUS_ONE = Byte.valueOf((byte) -1); - /** Reusable Double constant for zero. */ - public static final Double DOUBLE_ZERO = Double.valueOf(0.0d); - /** Reusable Double constant for one. */ - public static final Double DOUBLE_ONE = Double.valueOf(1.0d); - /** Reusable Double constant for minus one. */ - public static final Double DOUBLE_MINUS_ONE = Double.valueOf(-1.0d); - /** Reusable Float constant for zero. */ - public static final Float FLOAT_ZERO = Float.valueOf(0.0f); - /** Reusable Float constant for one. */ - public static final Float FLOAT_ONE = Float.valueOf(1.0f); - /** Reusable Float constant for minus one. */ - public static final Float FLOAT_MINUS_ONE = Float.valueOf(-1.0f); - - /** - * {@link Integer#MAX_VALUE} as a {@link Long}. - * - * @since 3.12.0 - */ - public static final Long LONG_INT_MAX_VALUE = Long.valueOf(Integer.MAX_VALUE); - - /** - * {@link Integer#MIN_VALUE} as a {@link Long}. - * - * @since 3.12.0 - */ - public static final Long LONG_INT_MIN_VALUE = Long.valueOf(Integer.MIN_VALUE); - - /** - *

- * {@code NumberUtils} instances should NOT be constructed in standard - * programming. Instead, the class should be used as - * {@code NumberUtils.toInt("6");}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public NumberUtils() { - } - - // ----------------------------------------------------------------------- - /** - *

- * Convert a {@code String} to an {@code int}, returning {@code zero} if the - * conversion fails. - *

- * - *

- * If the string is {@code null}, {@code zero} is returned. - *

- * - *
-	 *   NumberUtils.toInt(null) = 0
-	 *   NumberUtils.toInt("")   = 0
-	 *   NumberUtils.toInt("1")  = 1
-	 * 
- * - * @param str the string to convert, may be null - * @return the int represented by the string, or {@code zero} if conversion - * fails - * @since 2.1 - */ - public static int toInt(final String str) { - return toInt(str, 0); - } - - /** - *

- * Convert a {@code String} to an {@code int}, returning a default value if the - * conversion fails. - *

- * - *

- * If the string is {@code null}, the default value is returned. - *

- * - *
-	 *   NumberUtils.toInt(null, 1) = 1
-	 *   NumberUtils.toInt("", 1)   = 1
-	 *   NumberUtils.toInt("1", 0)  = 1
-	 * 
- * - * @param str the string to convert, may be null - * @param defaultValue the default value - * @return the int represented by the string, or the default if conversion fails - * @since 2.1 - */ - public static int toInt(final String str, final int defaultValue) { - if (str == null) { - return defaultValue; - } - try { - return Integer.parseInt(str); - } catch (final NumberFormatException nfe) { - return defaultValue; - } - } - - /** - *

- * Convert a {@code String} to a {@code long}, returning {@code zero} if the - * conversion fails. - *

- * - *

- * If the string is {@code null}, {@code zero} is returned. - *

- * - *
-	 *   NumberUtils.toLong(null) = 0L
-	 *   NumberUtils.toLong("")   = 0L
-	 *   NumberUtils.toLong("1")  = 1L
-	 * 
- * - * @param str the string to convert, may be null - * @return the long represented by the string, or {@code 0} if conversion fails - * @since 2.1 - */ - public static long toLong(final String str) { - return toLong(str, 0L); - } - - /** - *

- * Convert a {@code String} to a {@code long}, returning a default value if the - * conversion fails. - *

- * - *

- * If the string is {@code null}, the default value is returned. - *

- * - *
-	 *   NumberUtils.toLong(null, 1L) = 1L
-	 *   NumberUtils.toLong("", 1L)   = 1L
-	 *   NumberUtils.toLong("1", 0L)  = 1L
-	 * 
- * - * @param str the string to convert, may be null - * @param defaultValue the default value - * @return the long represented by the string, or the default if conversion - * fails - * @since 2.1 - */ - public static long toLong(final String str, final long defaultValue) { - if (str == null) { - return defaultValue; - } - try { - return Long.parseLong(str); - } catch (final NumberFormatException nfe) { - return defaultValue; - } - } - - /** - *

- * Convert a {@code String} to a {@code float}, returning {@code 0.0f} if the - * conversion fails. - *

- * - *

- * If the string {@code str} is {@code null}, {@code 0.0f} is returned. - *

- * - *
-	 *   NumberUtils.toFloat(null)   = 0.0f
-	 *   NumberUtils.toFloat("")     = 0.0f
-	 *   NumberUtils.toFloat("1.5")  = 1.5f
-	 * 
- * - * @param str the string to convert, may be {@code null} - * @return the float represented by the string, or {@code 0.0f} if conversion - * fails - * @since 2.1 - */ - public static float toFloat(final String str) { - return toFloat(str, 0.0f); - } - - /** - *

- * Convert a {@code String} to a {@code float}, returning a default value if the - * conversion fails. - *

- * - *

- * If the string {@code str} is {@code null}, the default value is returned. - *

- * - *
-	 *   NumberUtils.toFloat(null, 1.1f)   = 1.0f
-	 *   NumberUtils.toFloat("", 1.1f)     = 1.1f
-	 *   NumberUtils.toFloat("1.5", 0.0f)  = 1.5f
-	 * 
- * - * @param str the string to convert, may be {@code null} - * @param defaultValue the default value - * @return the float represented by the string, or defaultValue if conversion - * fails - * @since 2.1 - */ - public static float toFloat(final String str, final float defaultValue) { - if (str == null) { - return defaultValue; - } - try { - return Float.parseFloat(str); - } catch (final NumberFormatException nfe) { - return defaultValue; - } - } - - /** - *

- * Convert a {@code String} to a {@code double}, returning {@code 0.0d} if the - * conversion fails. - *

- * - *

- * If the string {@code str} is {@code null}, {@code 0.0d} is returned. - *

- * - *
-	 *   NumberUtils.toDouble(null)   = 0.0d
-	 *   NumberUtils.toDouble("")     = 0.0d
-	 *   NumberUtils.toDouble("1.5")  = 1.5d
-	 * 
- * - * @param str the string to convert, may be {@code null} - * @return the double represented by the string, or {@code 0.0d} if conversion - * fails - * @since 2.1 - */ - public static double toDouble(final String str) { - return toDouble(str, 0.0d); - } - - /** - *

- * Convert a {@code String} to a {@code double}, returning a default value if - * the conversion fails. - *

- * - *

- * If the string {@code str} is {@code null}, the default value is returned. - *

- * - *
-	 *   NumberUtils.toDouble(null, 1.1d)   = 1.1d
-	 *   NumberUtils.toDouble("", 1.1d)     = 1.1d
-	 *   NumberUtils.toDouble("1.5", 0.0d)  = 1.5d
-	 * 
- * - * @param str the string to convert, may be {@code null} - * @param defaultValue the default value - * @return the double represented by the string, or defaultValue if conversion - * fails - * @since 2.1 - */ - public static double toDouble(final String str, final double defaultValue) { - if (str == null) { - return defaultValue; - } - try { - return Double.parseDouble(str); - } catch (final NumberFormatException nfe) { - return defaultValue; - } - } - - /** - *

- * Convert a {@code BigDecimal} to a {@code double}. - *

- * - *

- * If the {@code BigDecimal} {@code value} is {@code null}, then the specified - * default value is returned. - *

- * - *
-	 *   NumberUtils.toDouble(null)                     = 0.0d
-	 *   NumberUtils.toDouble(BigDecimal.valudOf(8.5d)) = 8.5d
-	 * 
- * - * @param value the {@code BigDecimal} to convert, may be {@code null}. - * @return the double represented by the {@code BigDecimal} or {@code 0.0d} if - * the {@code BigDecimal} is {@code null}. - * @since 3.8 - */ - public static double toDouble(final BigDecimal value) { - return toDouble(value, 0.0d); - } - - /** - *

- * Convert a {@code BigDecimal} to a {@code double}. - *

- * - *

- * If the {@code BigDecimal} {@code value} is {@code null}, then the specified - * default value is returned. - *

- * - *
-	 *   NumberUtils.toDouble(null, 1.1d)                     = 1.1d
-	 *   NumberUtils.toDouble(BigDecimal.valudOf(8.5d), 1.1d) = 8.5d
-	 * 
- * - * @param value the {@code BigDecimal} to convert, may be {@code null}. - * @param defaultValue the default value - * @return the double represented by the {@code BigDecimal} or the defaultValue - * if the {@code BigDecimal} is {@code null}. - * @since 3.8 - */ - public static double toDouble(final BigDecimal value, final double defaultValue) { - return value == null ? defaultValue : value.doubleValue(); - } - - // ----------------------------------------------------------------------- - /** - *

- * Convert a {@code String} to a {@code byte}, returning {@code zero} if the - * conversion fails. - *

- * - *

- * If the string is {@code null}, {@code zero} is returned. - *

- * - *
-	 *   NumberUtils.toByte(null) = 0
-	 *   NumberUtils.toByte("")   = 0
-	 *   NumberUtils.toByte("1")  = 1
-	 * 
- * - * @param str the string to convert, may be null - * @return the byte represented by the string, or {@code zero} if conversion - * fails - * @since 2.5 - */ - public static byte toByte(final String str) { - return toByte(str, (byte) 0); - } - - /** - *

- * Convert a {@code String} to a {@code byte}, returning a default value if the - * conversion fails. - *

- * - *

- * If the string is {@code null}, the default value is returned. - *

- * - *
-	 *   NumberUtils.toByte(null, 1) = 1
-	 *   NumberUtils.toByte("", 1)   = 1
-	 *   NumberUtils.toByte("1", 0)  = 1
-	 * 
- * - * @param str the string to convert, may be null - * @param defaultValue the default value - * @return the byte represented by the string, or the default if conversion - * fails - * @since 2.5 - */ - public static byte toByte(final String str, final byte defaultValue) { - if (str == null) { - return defaultValue; - } - try { - return Byte.parseByte(str); - } catch (final NumberFormatException nfe) { - return defaultValue; - } - } - - /** - *

- * Convert a {@code String} to a {@code short}, returning {@code zero} if the - * conversion fails. - *

- * - *

- * If the string is {@code null}, {@code zero} is returned. - *

- * - *
-	 *   NumberUtils.toShort(null) = 0
-	 *   NumberUtils.toShort("")   = 0
-	 *   NumberUtils.toShort("1")  = 1
-	 * 
- * - * @param str the string to convert, may be null - * @return the short represented by the string, or {@code zero} if conversion - * fails - * @since 2.5 - */ - public static short toShort(final String str) { - return toShort(str, (short) 0); - } - - /** - *

- * Convert a {@code String} to an {@code short}, returning a default value if - * the conversion fails. - *

- * - *

- * If the string is {@code null}, the default value is returned. - *

- * - *
-	 *   NumberUtils.toShort(null, 1) = 1
-	 *   NumberUtils.toShort("", 1)   = 1
-	 *   NumberUtils.toShort("1", 0)  = 1
-	 * 
- * - * @param str the string to convert, may be null - * @param defaultValue the default value - * @return the short represented by the string, or the default if conversion - * fails - * @since 2.5 - */ - public static short toShort(final String str, final short defaultValue) { - if (str == null) { - return defaultValue; - } - try { - return Short.parseShort(str); - } catch (final NumberFormatException nfe) { - return defaultValue; - } - } - - /** - * Convert a {@code BigDecimal} to a {@code BigDecimal} with a scale of two that - * has been rounded using {@code RoundingMode.HALF_EVEN}. If the supplied - * {@code value} is null, then {@code BigDecimal.ZERO} is returned. - * - *

- * Note, the scale of a {@code BigDecimal} is the number of digits to the right - * of the decimal point. - *

- * - * @param value the {@code BigDecimal} to convert, may be null. - * @return the scaled, with appropriate rounding, {@code BigDecimal}. - * @since 3.8 - */ - public static BigDecimal toScaledBigDecimal(final BigDecimal value) { - return toScaledBigDecimal(value, INTEGER_TWO, RoundingMode.HALF_EVEN); - } - - /** - * Convert a {@code BigDecimal} to a {@code BigDecimal} whose scale is the - * specified value with a {@code RoundingMode} applied. If the input - * {@code value} is {@code null}, we simply return {@code BigDecimal.ZERO}. - * - * @param value the {@code BigDecimal} to convert, may be null. - * @param scale the number of digits to the right of the decimal point. - * @param roundingMode a rounding behavior for numerical operations capable of - * discarding precision. - * @return the scaled, with appropriate rounding, {@code BigDecimal}. - * @since 3.8 - */ - public static BigDecimal toScaledBigDecimal(final BigDecimal value, final int scale, - final RoundingMode roundingMode) { - if (value == null) { - return BigDecimal.ZERO; - } - return value.setScale(scale, (roundingMode == null) ? RoundingMode.HALF_EVEN : roundingMode); - } - - /** - * Convert a {@code Float} to a {@code BigDecimal} with a scale of two that has - * been rounded using {@code RoundingMode.HALF_EVEN}. If the supplied - * {@code value} is null, then {@code BigDecimal.ZERO} is returned. - * - *

- * Note, the scale of a {@code BigDecimal} is the number of digits to the right - * of the decimal point. - *

- * - * @param value the {@code Float} to convert, may be null. - * @return the scaled, with appropriate rounding, {@code BigDecimal}. - * @since 3.8 - */ - public static BigDecimal toScaledBigDecimal(final Float value) { - return toScaledBigDecimal(value, INTEGER_TWO, RoundingMode.HALF_EVEN); - } - - /** - * Convert a {@code Float} to a {@code BigDecimal} whose scale is the specified - * value with a {@code RoundingMode} applied. If the input {@code value} is - * {@code null}, we simply return {@code BigDecimal.ZERO}. - * - * @param value the {@code Float} to convert, may be null. - * @param scale the number of digits to the right of the decimal point. - * @param roundingMode a rounding behavior for numerical operations capable of - * discarding precision. - * @return the scaled, with appropriate rounding, {@code BigDecimal}. - * @since 3.8 - */ - public static BigDecimal toScaledBigDecimal(final Float value, final int scale, final RoundingMode roundingMode) { - if (value == null) { - return BigDecimal.ZERO; - } - return toScaledBigDecimal(BigDecimal.valueOf(value), scale, roundingMode); - } - - /** - * Convert a {@code Double} to a {@code BigDecimal} with a scale of two that has - * been rounded using {@code RoundingMode.HALF_EVEN}. If the supplied - * {@code value} is null, then {@code BigDecimal.ZERO} is returned. - * - *

- * Note, the scale of a {@code BigDecimal} is the number of digits to the right - * of the decimal point. - *

- * - * @param value the {@code Double} to convert, may be null. - * @return the scaled, with appropriate rounding, {@code BigDecimal}. - * @since 3.8 - */ - public static BigDecimal toScaledBigDecimal(final Double value) { - return toScaledBigDecimal(value, INTEGER_TWO, RoundingMode.HALF_EVEN); - } - - /** - * Convert a {@code Double} to a {@code BigDecimal} whose scale is the specified - * value with a {@code RoundingMode} applied. If the input {@code value} is - * {@code null}, we simply return {@code BigDecimal.ZERO}. - * - * @param value the {@code Double} to convert, may be null. - * @param scale the number of digits to the right of the decimal point. - * @param roundingMode a rounding behavior for numerical operations capable of - * discarding precision. - * @return the scaled, with appropriate rounding, {@code BigDecimal}. - * @since 3.8 - */ - public static BigDecimal toScaledBigDecimal(final Double value, final int scale, final RoundingMode roundingMode) { - if (value == null) { - return BigDecimal.ZERO; - } - return toScaledBigDecimal(BigDecimal.valueOf(value), scale, roundingMode); - } - - /** - * Convert a {@code String} to a {@code BigDecimal} with a scale of two that has - * been rounded using {@code RoundingMode.HALF_EVEN}. If the supplied - * {@code value} is null, then {@code BigDecimal.ZERO} is returned. - * - *

- * Note, the scale of a {@code BigDecimal} is the number of digits to the right - * of the decimal point. - *

- * - * @param value the {@code String} to convert, may be null. - * @return the scaled, with appropriate rounding, {@code BigDecimal}. - * @since 3.8 - */ - public static BigDecimal toScaledBigDecimal(final String value) { - return toScaledBigDecimal(value, INTEGER_TWO, RoundingMode.HALF_EVEN); - } - - /** - * Convert a {@code String} to a {@code BigDecimal} whose scale is the specified - * value with a {@code RoundingMode} applied. If the input {@code value} is - * {@code null}, we simply return {@code BigDecimal.ZERO}. - * - * @param value the {@code String} to convert, may be null. - * @param scale the number of digits to the right of the decimal point. - * @param roundingMode a rounding behavior for numerical operations capable of - * discarding precision. - * @return the scaled, with appropriate rounding, {@code BigDecimal}. - * @since 3.8 - */ - public static BigDecimal toScaledBigDecimal(final String value, final int scale, final RoundingMode roundingMode) { - if (value == null) { - return BigDecimal.ZERO; - } - return toScaledBigDecimal(createBigDecimal(value), scale, roundingMode); - } - - // ----------------------------------------------------------------------- - // must handle Long, Float, Integer, Float, Short, - // BigDecimal, BigInteger and Byte - // useful methods: - // Byte.decode(String) - // Byte.valueOf(String, int radix) - // Byte.valueOf(String) - // Double.valueOf(String) - // Float.valueOf(String) - // Float.valueOf(String) - // Integer.valueOf(String, int radix) - // Integer.valueOf(String) - // Integer.decode(String) - // Integer.getInteger(String) - // Integer.getInteger(String, int val) - // Integer.getInteger(String, Integer val) - // Integer.valueOf(String) - // Double.valueOf(String) - // new Byte(String) - // Long.valueOf(String) - // Long.getLong(String) - // Long.getLong(String, int) - // Long.getLong(String, Integer) - // Long.valueOf(String, int) - // Long.valueOf(String) - // Short.valueOf(String) - // Short.decode(String) - // Short.valueOf(String, int) - // Short.valueOf(String) - // new BigDecimal(String) - // new BigInteger(String) - // new BigInteger(String, int radix) - // Possible inputs: - // 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd - // plus minus everything. Prolly more. A lot are not separable. - - /** - *

- * Turns a string value into a java.lang.Number. - *

- * - *

- * If the string starts with {@code 0x} or {@code -0x} (lower or upper case) or - * {@code #} or {@code -#}, it will be interpreted as a hexadecimal Integer - or - * Long, if the number of digits after the prefix is more than 8 - or BigInteger - * if there are more than 16 digits. - *

- *

- * Then, the value is examined for a type qualifier on the end, i.e. one of - * {@code 'f', 'F', 'd', 'D', 'l', 'L'}. If it is found, it starts trying to - * create successively larger types from the type specified until one is found - * that can represent the value. - *

- * - *

- * If a type specifier is not found, it will check for a decimal point and then - * try successively larger types from {@code Integer} to {@code BigInteger} and - * from {@code Float} to {@code BigDecimal}. - *

- * - *

- * Integral values with a leading {@code 0} will be interpreted as octal; the - * returned number will be Integer, Long or BigDecimal as appropriate. - *

- * - *

- * Returns {@code null} if the string is {@code null}. - *

- * - *

- * This method does not trim the input string, i.e., strings with leading or - * trailing spaces will generate NumberFormatExceptions. - *

- * - * @param str String containing a number, may be null - * @return Number created from the string (or null if the input is null) - * @throws NumberFormatException if the value cannot be converted - */ - public static Number createNumber(final String str) { - if (str == null) { - return null; - } - if (StringUtils.isBlank(str)) { - throw new NumberFormatException("A blank string is not a valid number"); - } - // Need to deal with all possible hex prefixes here - final String[] hex_prefixes = { "0x", "0X", "-0x", "-0X", "#", "-#" }; - final int length = str.length(); - int pfxLen = 0; - for (final String pfx : hex_prefixes) { - if (str.startsWith(pfx)) { - pfxLen += pfx.length(); - break; - } - } - if (pfxLen > 0) { // we have a hex number - char firstSigDigit = 0; // strip leading zeroes - for (int i = pfxLen; i < length; i++) { - firstSigDigit = str.charAt(i); - if (firstSigDigit == '0') { // count leading zeroes - pfxLen++; - } else { - break; - } - } - final int hexDigits = length - pfxLen; - if (hexDigits > 16 || hexDigits == 16 && firstSigDigit > '7') { // too many for Long - return createBigInteger(str); - } - if (hexDigits > 8 || hexDigits == 8 && firstSigDigit > '7') { // too many for an int - return createLong(str); - } - return createInteger(str); - } - final char lastChar = str.charAt(length - 1); - final String mant; - final String dec; - final String exp; - final int decPos = str.indexOf('.'); - final int expPos = str.indexOf('e') + str.indexOf('E') + 1; // assumes both not present - // if both e and E are present, this is caught by the checks on expPos (which - // prevent IOOBE) - // and the parsing which will detect if e or E appear in a number due to using - // the wrong offset - - if (decPos > -1) { // there is a decimal point - if (expPos > -1) { // there is an exponent - if (expPos < decPos || expPos > length) { // prevents double exponent causing IOOBE - throw new NumberFormatException(str + " is not a valid number."); - } - dec = str.substring(decPos + 1, expPos); - } else { - dec = str.substring(decPos + 1); - } - mant = getMantissa(str, decPos); - } else { - if (expPos > -1) { - if (expPos > length) { // prevents double exponent causing IOOBE - throw new NumberFormatException(str + " is not a valid number."); - } - mant = getMantissa(str, expPos); - } else { - mant = getMantissa(str); - } - dec = null; - } - if (!Character.isDigit(lastChar) && lastChar != '.') { - if (expPos > -1 && expPos < length - 1) { - exp = str.substring(expPos + 1, length - 1); - } else { - exp = null; - } - // Requesting a specific type.. - final String numeric = str.substring(0, length - 1); - final boolean allZeros = isAllZeros(mant) && isAllZeros(exp); - switch (lastChar) { - case 'l': - case 'L': - if (dec == null && exp == null - && (!numeric.isEmpty() && numeric.charAt(0) == '-' && isDigits(numeric.substring(1)) - || isDigits(numeric))) { - try { - return createLong(numeric); - } catch (final NumberFormatException nfe) { // NOPMD - // Too big for a long - } - return createBigInteger(numeric); - - } - throw new NumberFormatException(str + " is not a valid number."); - case 'f': - case 'F': - try { - final Float f = createFloat(str); - if (!(f.isInfinite() || f.floatValue() == 0.0F && !allZeros)) { - // If it's too big for a float or the float value = 0 and the string - // has non-zeros in it, then float does not have the precision we want - return f; - } - - } catch (final NumberFormatException nfe) { // NOPMD - // ignore the bad number - } - //$FALL-THROUGH$ - case 'd': - case 'D': - try { - final Double d = createDouble(str); - if (!(d.isInfinite() || d.doubleValue() == 0.0D && !allZeros)) { - return d; - } - } catch (final NumberFormatException nfe) { // NOPMD - // ignore the bad number - } - try { - return createBigDecimal(numeric); - } catch (final NumberFormatException e) { // NOPMD - // ignore the bad number - } - //$FALL-THROUGH$ - default: - throw new NumberFormatException(str + " is not a valid number."); - - } - } - // User doesn't have a preference on the return type, so let's start - // small and go from there... - if (expPos > -1 && expPos < length - 1) { - exp = str.substring(expPos + 1); - } else { - exp = null; - } - if (dec == null && exp == null) { // no decimal point and no exponent - // Must be an Integer, Long, Biginteger - try { - return createInteger(str); - } catch (final NumberFormatException nfe) { // NOPMD - // ignore the bad number - } - try { - return createLong(str); - } catch (final NumberFormatException nfe) { // NOPMD - // ignore the bad number - } - return createBigInteger(str); - } - - // Must be a Float, Double, BigDecimal - final boolean allZeros = isAllZeros(mant) && isAllZeros(exp); - try { - final Float f = createFloat(str); - final Double d = createDouble(str); - if (!f.isInfinite() && !(f.floatValue() == 0.0F && !allZeros) && f.toString().equals(d.toString())) { - return f; - } - if (!d.isInfinite() && !(d.doubleValue() == 0.0D && !allZeros)) { - final BigDecimal b = createBigDecimal(str); - if (b.compareTo(BigDecimal.valueOf(d.doubleValue())) == 0) { - return d; - } - return b; - } - } catch (final NumberFormatException nfe) { // NOPMD - // ignore the bad number - } - return createBigDecimal(str); - } - - /** - *

- * Utility method for {@link #createNumber(java.lang.String)}. - *

- * - *

- * Returns mantissa of the given number. - *

- * - * @param str the string representation of the number - * @return mantissa of the given number - */ - private static String getMantissa(final String str) { - return getMantissa(str, str.length()); - } - - /** - *

- * Utility method for {@link #createNumber(java.lang.String)}. - *

- * - *

- * Returns mantissa of the given number. - *

- * - * @param str the string representation of the number - * @param stopPos the position of the exponent or decimal point - * @return mantissa of the given number - */ - private static String getMantissa(final String str, final int stopPos) { - final char firstChar = str.charAt(0); - final boolean hasSign = firstChar == '-' || firstChar == '+'; - - return hasSign ? str.substring(1, stopPos) : str.substring(0, stopPos); - } - - /** - *

- * Utility method for {@link #createNumber(java.lang.String)}. - *

- * - *

- * Returns {@code true} if s is {@code null}. - *

- * - * @param str the String to check - * @return if it is all zeros or {@code null} - */ - private static boolean isAllZeros(final String str) { - if (str == null) { - return true; - } - for (int i = str.length() - 1; i >= 0; i--) { - if (str.charAt(i) != '0') { - return false; - } - } - return !str.isEmpty(); - } - - // ----------------------------------------------------------------------- - /** - *

- * Convert a {@code String} to a {@code Float}. - *

- * - *

- * Returns {@code null} if the string is {@code null}. - *

- * - * @param str a {@code String} to convert, may be null - * @return converted {@code Float} (or null if the input is null) - * @throws NumberFormatException if the value cannot be converted - */ - public static Float createFloat(final String str) { - if (str == null) { - return null; - } - return Float.valueOf(str); - } - - /** - *

- * Convert a {@code String} to a {@code Double}. - *

- * - *

- * Returns {@code null} if the string is {@code null}. - *

- * - * @param str a {@code String} to convert, may be null - * @return converted {@code Double} (or null if the input is null) - * @throws NumberFormatException if the value cannot be converted - */ - public static Double createDouble(final String str) { - if (str == null) { - return null; - } - return Double.valueOf(str); - } - - /** - *

- * Convert a {@code String} to a {@code Integer}, handling hex (0xhhhh) and - * octal (0dddd) notations. N.B. a leading zero means octal; spaces are not - * trimmed. - *

- * - *

- * Returns {@code null} if the string is {@code null}. - *

- * - * @param str a {@code String} to convert, may be null - * @return converted {@code Integer} (or null if the input is null) - * @throws NumberFormatException if the value cannot be converted - */ - public static Integer createInteger(final String str) { - if (str == null) { - return null; - } - // decode() handles 0xAABD and 0777 (hex and octal) as well. - return Integer.decode(str); - } - - /** - *

- * Convert a {@code String} to a {@code Long}; since 3.1 it handles hex (0Xhhhh) - * and octal (0ddd) notations. N.B. a leading zero means octal; spaces are not - * trimmed. - *

- * - *

- * Returns {@code null} if the string is {@code null}. - *

- * - * @param str a {@code String} to convert, may be null - * @return converted {@code Long} (or null if the input is null) - * @throws NumberFormatException if the value cannot be converted - */ - public static Long createLong(final String str) { - if (str == null) { - return null; - } - return Long.decode(str); - } - - /** - *

- * Convert a {@code String} to a {@code BigInteger}; since 3.2 it handles hex - * (0x or #) and octal (0) notations. - *

- * - *

- * Returns {@code null} if the string is {@code null}. - *

- * - * @param str a {@code String} to convert, may be null - * @return converted {@code BigInteger} (or null if the input is null) - * @throws NumberFormatException if the value cannot be converted - */ - public static BigInteger createBigInteger(final String str) { - if (str == null) { - return null; - } - int pos = 0; // offset within string - int radix = 10; - boolean negate = false; // need to negate later? - if (str.startsWith("-")) { - negate = true; - pos = 1; - } - if (str.startsWith("0x", pos) || str.startsWith("0X", pos)) { // hex - radix = 16; - pos += 2; - } else if (str.startsWith("#", pos)) { // alternative hex (allowed by Long/Integer) - radix = 16; - pos++; - } else if (str.startsWith("0", pos) && str.length() > pos + 1) { // octal; so long as there are additional - // digits - radix = 8; - pos++; - } // default is to treat as decimal - - final BigInteger value = new BigInteger(str.substring(pos), radix); - return negate ? value.negate() : value; - } - - /** - *

- * Convert a {@code String} to a {@code BigDecimal}. - *

- * - *

- * Returns {@code null} if the string is {@code null}. - *

- * - * @param str a {@code String} to convert, may be null - * @return converted {@code BigDecimal} (or null if the input is null) - * @throws NumberFormatException if the value cannot be converted - */ - public static BigDecimal createBigDecimal(final String str) { - if (str == null) { - return null; - } - // handle JDK1.3.1 bug where "" throws IndexOutOfBoundsException - if (StringUtils.isBlank(str)) { - throw new NumberFormatException("A blank string is not a valid number"); - } - return new BigDecimal(str); - } - - // Min in array - // -------------------------------------------------------------------- - /** - *

- * Returns the minimum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the minimum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from min(long[]) to min(long...) - */ - public static long min(final long... array) { - // Validates input - validateArray(array); - - // Finds and returns min - long min = array[0]; - for (int i = 1; i < array.length; i++) { - if (array[i] < min) { - min = array[i]; - } - } - - return min; - } - - /** - *

- * Returns the minimum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the minimum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from min(int[]) to min(int...) - */ - public static int min(final int... array) { - // Validates input - validateArray(array); - - // Finds and returns min - int min = array[0]; - for (int j = 1; j < array.length; j++) { - if (array[j] < min) { - min = array[j]; - } - } - - return min; - } - - /** - *

- * Returns the minimum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the minimum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from min(short[]) to min(short...) - */ - public static short min(final short... array) { - // Validates input - validateArray(array); - - // Finds and returns min - short min = array[0]; - for (int i = 1; i < array.length; i++) { - if (array[i] < min) { - min = array[i]; - } - } - - return min; - } - - /** - *

- * Returns the minimum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the minimum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from min(byte[]) to min(byte...) - */ - public static byte min(final byte... array) { - // Validates input - validateArray(array); - - // Finds and returns min - byte min = array[0]; - for (int i = 1; i < array.length; i++) { - if (array[i] < min) { - min = array[i]; - } - } - - return min; - } - - /** - *

- * Returns the minimum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the minimum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @see IEEE754rUtils#min(double[]) IEEE754rUtils for a version of this method - * that handles NaN differently - * @since 3.4 Changed signature from min(double[]) to min(double...) - */ - public static double min(final double... array) { - // Validates input - validateArray(array); - - // Finds and returns min - double min = array[0]; - for (int i = 1; i < array.length; i++) { - if (Double.isNaN(array[i])) { - return Double.NaN; - } - if (array[i] < min) { - min = array[i]; - } - } - - return min; - } - - /** - *

- * Returns the minimum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the minimum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @see IEEE754rUtils#min(float[]) IEEE754rUtils for a version of this method - * that handles NaN differently - * @since 3.4 Changed signature from min(float[]) to min(float...) - */ - public static float min(final float... array) { - // Validates input - validateArray(array); - - // Finds and returns min - float min = array[0]; - for (int i = 1; i < array.length; i++) { - if (Float.isNaN(array[i])) { - return Float.NaN; - } - if (array[i] < min) { - min = array[i]; - } - } - - return min; - } - - // Max in array - // -------------------------------------------------------------------- - /** - *

- * Returns the maximum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the maximum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from max(long[]) to max(long...) - */ - public static long max(final long... array) { - // Validates input - validateArray(array); - - // Finds and returns max - long max = array[0]; - for (int j = 1; j < array.length; j++) { - if (array[j] > max) { - max = array[j]; - } - } - - return max; - } - - /** - *

- * Returns the maximum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the maximum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from max(int[]) to max(int...) - */ - public static int max(final int... array) { - // Validates input - validateArray(array); - - // Finds and returns max - int max = array[0]; - for (int j = 1; j < array.length; j++) { - if (array[j] > max) { - max = array[j]; - } - } - - return max; - } - - /** - *

- * Returns the maximum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the maximum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from max(short[]) to max(short...) - */ - public static short max(final short... array) { - // Validates input - validateArray(array); - - // Finds and returns max - short max = array[0]; - for (int i = 1; i < array.length; i++) { - if (array[i] > max) { - max = array[i]; - } - } - - return max; - } - - /** - *

- * Returns the maximum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the maximum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @since 3.4 Changed signature from max(byte[]) to max(byte...) - */ - public static byte max(final byte... array) { - // Validates input - validateArray(array); - - // Finds and returns max - byte max = array[0]; - for (int i = 1; i < array.length; i++) { - if (array[i] > max) { - max = array[i]; - } - } - - return max; - } - - /** - *

- * Returns the maximum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the maximum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @see IEEE754rUtils#max(double[]) IEEE754rUtils for a version of this method - * that handles NaN differently - * @since 3.4 Changed signature from max(double[]) to max(double...) - */ - public static double max(final double... array) { - // Validates input - validateArray(array); - - // Finds and returns max - double max = array[0]; - for (int j = 1; j < array.length; j++) { - if (Double.isNaN(array[j])) { - return Double.NaN; - } - if (array[j] > max) { - max = array[j]; - } - } - - return max; - } - - /** - *

- * Returns the maximum value in an array. - *

- * - * @param array an array, must not be null or empty - * @return the maximum value in the array - * @throws IllegalArgumentException if {@code array} is {@code null} - * @throws IllegalArgumentException if {@code array} is empty - * @see IEEE754rUtils#max(float[]) IEEE754rUtils for a version of this method - * that handles NaN differently - * @since 3.4 Changed signature from max(float[]) to max(float...) - */ - public static float max(final float... array) { - // Validates input - validateArray(array); - - // Finds and returns max - float max = array[0]; - for (int j = 1; j < array.length; j++) { - if (Float.isNaN(array[j])) { - return Float.NaN; - } - if (array[j] > max) { - max = array[j]; - } - } - - return max; - } - - /** - * Checks if the specified array is neither null nor empty. - * - * @param array the array to check - * @throws IllegalArgumentException if {@code array} is either {@code null} or - * empty - */ - private static void validateArray(final Object array) { - Validate.notNull(array, "array"); - Validate.isTrue(Array.getLength(array) != 0, "Array cannot be empty."); - } - - // 3 param min - // ----------------------------------------------------------------------- - /** - *

- * Gets the minimum of three {@code long} values. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the smallest of the values - */ - public static long min(long a, final long b, final long c) { - if (b < a) { - a = b; - } - if (c < a) { - a = c; - } - return a; - } - - /** - *

- * Gets the minimum of three {@code int} values. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the smallest of the values - */ - public static int min(int a, final int b, final int c) { - if (b < a) { - a = b; - } - if (c < a) { - a = c; - } - return a; - } - - /** - *

- * Gets the minimum of three {@code short} values. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the smallest of the values - */ - public static short min(short a, final short b, final short c) { - if (b < a) { - a = b; - } - if (c < a) { - a = c; - } - return a; - } - - /** - *

- * Gets the minimum of three {@code byte} values. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the smallest of the values - */ - public static byte min(byte a, final byte b, final byte c) { - if (b < a) { - a = b; - } - if (c < a) { - a = c; - } - return a; - } - - /** - *

- * Gets the minimum of three {@code double} values. - *

- * - *

- * If any value is {@code NaN}, {@code NaN} is returned. Infinity is handled. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the smallest of the values - * @see IEEE754rUtils#min(double, double, double) for a version of this method - * that handles NaN differently - */ - public static double min(final double a, final double b, final double c) { - return Math.min(Math.min(a, b), c); - } - - /** - *

- * Gets the minimum of three {@code float} values. - *

- * - *

- * If any value is {@code NaN}, {@code NaN} is returned. Infinity is handled. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the smallest of the values - * @see IEEE754rUtils#min(float, float, float) for a version of this method that - * handles NaN differently - */ - public static float min(final float a, final float b, final float c) { - return Math.min(Math.min(a, b), c); - } - - // 3 param max - // ----------------------------------------------------------------------- - /** - *

- * Gets the maximum of three {@code long} values. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the largest of the values - */ - public static long max(long a, final long b, final long c) { - if (b > a) { - a = b; - } - if (c > a) { - a = c; - } - return a; - } - - /** - *

- * Gets the maximum of three {@code int} values. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the largest of the values - */ - public static int max(int a, final int b, final int c) { - if (b > a) { - a = b; - } - if (c > a) { - a = c; - } - return a; - } - - /** - *

- * Gets the maximum of three {@code short} values. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the largest of the values - */ - public static short max(short a, final short b, final short c) { - if (b > a) { - a = b; - } - if (c > a) { - a = c; - } - return a; - } - - /** - *

- * Gets the maximum of three {@code byte} values. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the largest of the values - */ - public static byte max(byte a, final byte b, final byte c) { - if (b > a) { - a = b; - } - if (c > a) { - a = c; - } - return a; - } - - /** - *

- * Gets the maximum of three {@code double} values. - *

- * - *

- * If any value is {@code NaN}, {@code NaN} is returned. Infinity is handled. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the largest of the values - * @see IEEE754rUtils#max(double, double, double) for a version of this method - * that handles NaN differently - */ - public static double max(final double a, final double b, final double c) { - return Math.max(Math.max(a, b), c); - } - - /** - *

- * Gets the maximum of three {@code float} values. - *

- * - *

- * If any value is {@code NaN}, {@code NaN} is returned. Infinity is handled. - *

- * - * @param a value 1 - * @param b value 2 - * @param c value 3 - * @return the largest of the values - * @see IEEE754rUtils#max(float, float, float) for a version of this method that - * handles NaN differently - */ - public static float max(final float a, final float b, final float c) { - return Math.max(Math.max(a, b), c); - } - - // ----------------------------------------------------------------------- - /** - *

- * Checks whether the {@code String} contains only digit characters. - *

- * - *

- * {@code Null} and empty String will return {@code false}. - *

- * - * @param str the {@code String} to check - * @return {@code true} if str contains only Unicode numeric - */ - public static boolean isDigits(final String str) { - return StringUtils.isNumeric(str); - } - - /** - *

- * Checks whether the String a valid Java number. - *

- * - *

- * Valid numbers include hexadecimal marked with the {@code 0x} or {@code 0X} - * qualifier, octal numbers, scientific notation and numbers marked with a type - * qualifier (e.g. 123L). - *

- * - *

- * Non-hexadecimal strings beginning with a leading zero are treated as octal - * values. Thus the string {@code 09} will return {@code false}, since {@code 9} - * is not a valid octal value. However, numbers beginning with {@code 0.} are - * treated as decimal. - *

- * - *

- * {@code null} and empty/blank {@code String} will return {@code false}. - *

- * - *

- * Note, {@link #createNumber(String)} should return a number for every input - * resulting in {@code true}. - *

- * - * @param str the {@code String} to check - * @return {@code true} if the string is a correctly formatted number - * @since 3.3 the code supports hex {@code 0Xhhh} an octal {@code 0ddd} - * validation - * @deprecated This feature will be removed in Lang 4.0, use - * {@link NumberUtils#isCreatable(String)} instead - */ - @Deprecated - public static boolean isNumber(final String str) { - return isCreatable(str); - } - - /** - *

- * Checks whether the String a valid Java number. - *

- * - *

- * Valid numbers include hexadecimal marked with the {@code 0x} or {@code 0X} - * qualifier, octal numbers, scientific notation and numbers marked with a type - * qualifier (e.g. 123L). - *

- * - *

- * Non-hexadecimal strings beginning with a leading zero are treated as octal - * values. Thus the string {@code 09} will return {@code false}, since {@code 9} - * is not a valid octal value. However, numbers beginning with {@code 0.} are - * treated as decimal. - *

- * - *

- * {@code null} and empty/blank {@code String} will return {@code false}. - *

- * - *

- * Note, {@link #createNumber(String)} should return a number for every input - * resulting in {@code true}. - *

- * - * @param str the {@code String} to check - * @return {@code true} if the string is a correctly formatted number - * @since 3.5 - */ - public static boolean isCreatable(final String str) { - if (StringUtils.isEmpty(str)) { - return false; - } - final char[] chars = str.toCharArray(); - int sz = chars.length; - boolean hasExp = false; - boolean hasDecPoint = false; - boolean allowSigns = false; - boolean foundDigit = false; - // deal with any possible sign up front - final int start = chars[0] == '-' || chars[0] == '+' ? 1 : 0; - if (sz > start + 1 && chars[start] == '0' && !StringUtils.contains(str, '.')) { // leading 0, skip if is a - // decimal number - if (chars[start + 1] == 'x' || chars[start + 1] == 'X') { // leading 0x/0X - int i = start + 2; - if (i == sz) { - return false; // str == "0x" - } - // checking hex (it can't be anything else) - for (; i < chars.length; i++) { - if ((chars[i] < '0' || chars[i] > '9') && (chars[i] < 'a' || chars[i] > 'f') - && (chars[i] < 'A' || chars[i] > 'F')) { - return false; - } - } - return true; - } else if (Character.isDigit(chars[start + 1])) { - // leading 0, but not hex, must be octal - int i = start + 1; - for (; i < chars.length; i++) { - if (chars[i] < '0' || chars[i] > '7') { - return false; - } - } - return true; - } - } - sz--; // don't want to loop to the last char, check it afterwords - // for type qualifiers - int i = start; - // loop to the next to last char or to the last char if we need another digit to - // make a valid number (e.g. chars[0..5] = "1234E") - while (i < sz || i < sz + 1 && allowSigns && !foundDigit) { - if (chars[i] >= '0' && chars[i] <= '9') { - foundDigit = true; - allowSigns = false; - - } else if (chars[i] == '.') { - if (hasDecPoint || hasExp) { - // two decimal points or dec in exponent - return false; - } - hasDecPoint = true; - } else if (chars[i] == 'e' || chars[i] == 'E') { - // we've already taken care of hex. - if (hasExp) { - // two E's - return false; - } - if (!foundDigit) { - return false; - } - hasExp = true; - allowSigns = true; - } else if (chars[i] == '+' || chars[i] == '-') { - if (!allowSigns) { - return false; - } - allowSigns = false; - foundDigit = false; // we need a digit after the E - } else { - return false; - } - i++; - } - if (i < chars.length) { - if (chars[i] >= '0' && chars[i] <= '9') { - // no type qualifier, OK - return true; - } - if (chars[i] == 'e' || chars[i] == 'E') { - // can't have an E at the last byte - return false; - } - if (chars[i] == '.') { - if (hasDecPoint || hasExp) { - // two decimal points or dec in exponent - return false; - } - // single trailing decimal point after non-exponent is ok - return foundDigit; - } - if (!allowSigns && (chars[i] == 'd' || chars[i] == 'D' || chars[i] == 'f' || chars[i] == 'F')) { - return foundDigit; - } - if (chars[i] == 'l' || chars[i] == 'L') { - // not allowing L with an exponent or decimal point - return foundDigit && !hasExp && !hasDecPoint; - } - // last character is illegal - return false; - } - // allowSigns is true iff the val ends in 'E' - // found digit it to make sure weird stuff like '.' and '1E-' doesn't pass - return !allowSigns && foundDigit; - } - - /** - *

- * Checks whether the given String is a parsable number. - *

- * - *

- * Parsable numbers include those Strings understood by - * {@link Integer#parseInt(String)}, {@link Long#parseLong(String)}, - * {@link Float#parseFloat(String)} or {@link Double#parseDouble(String)}. This - * method can be used instead of catching {@link java.text.ParseException} when - * calling one of those methods. - *

- * - *

- * Hexadecimal and scientific notations are not considered - * parsable. See {@link #isCreatable(String)} on those cases. - *

- * - *

- * {@code Null} and empty String will return {@code false}. - *

- * - * @param str the String to check. - * @return {@code true} if the string is a parsable number. - * @since 3.4 - */ - public static boolean isParsable(final String str) { - if (StringUtils.isEmpty(str)) { - return false; - } - if (str.charAt(str.length() - 1) == '.') { - return false; - } - if (str.charAt(0) == '-') { - if (str.length() == 1) { - return false; - } - return withDecimalsParsing(str, 1); - } - return withDecimalsParsing(str, 0); - } - - private static boolean withDecimalsParsing(final String str, final int beginIdx) { - int decimalPoints = 0; - for (int i = beginIdx; i < str.length(); i++) { - final boolean isDecimalPoint = str.charAt(i) == '.'; - if (isDecimalPoint) { - decimalPoints++; - } - if (decimalPoints > 1) { - return false; - } - if (!isDecimalPoint && !Character.isDigit(str.charAt(i))) { - return false; - } - } - return true; - } - - /** - *

- * Compares two {@code int} values numerically. This is the same functionality - * as provided in Java 7. - *

- * - * @param x the first {@code int} to compare - * @param y the second {@code int} to compare - * @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if - * {@code x < y}; and a value greater than {@code 0} if {@code x > y} - * @since 3.4 - */ - public static int compare(final int x, final int y) { - if (x == y) { - return 0; - } - return x < y ? -1 : 1; - } - - /** - *

- * Compares to {@code long} values numerically. This is the same functionality - * as provided in Java 7. - *

- * - * @param x the first {@code long} to compare - * @param y the second {@code long} to compare - * @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if - * {@code x < y}; and a value greater than {@code 0} if {@code x > y} - * @since 3.4 - */ - public static int compare(final long x, final long y) { - if (x == y) { - return 0; - } - return x < y ? -1 : 1; - } - - /** - *

- * Compares to {@code short} values numerically. This is the same functionality - * as provided in Java 7. - *

- * - * @param x the first {@code short} to compare - * @param y the second {@code short} to compare - * @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if - * {@code x < y}; and a value greater than {@code 0} if {@code x > y} - * @since 3.4 - */ - public static int compare(final short x, final short y) { - if (x == y) { - return 0; - } - return x < y ? -1 : 1; - } - - /** - *

- * Compares two {@code byte} values numerically. This is the same functionality - * as provided in Java 7. - *

- * - * @param x the first {@code byte} to compare - * @param y the second {@code byte} to compare - * @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if - * {@code x < y}; and a value greater than {@code 0} if {@code x > y} - * @since 3.4 - */ - public static int compare(final byte x, final byte y) { - return x - y; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/math/package-info.java b/sources/main/java/org/apache/commons/lang3/math/package-info.java deleted file mode 100644 index 332d4273..00000000 --- a/sources/main/java/org/apache/commons/lang3/math/package-info.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - *

- * Extends {@link java.math} for business mathematical classes. This package is - * intended for business mathematical use, not scientific use. See - * Commons Math for a more - * complete set of mathematical classes. These classes are immutable, and - * therefore thread-safe. - *

- * - *

- * Although Commons Math also exists, some basic mathematical functions are - * contained within Lang. These include classes to a - * {@link org.apache.commons.lang3.math.Fraction} class, various utilities for - * random numbers, and the flagship class, - * {@link org.apache.commons.lang3.math.NumberUtils} which contains a handful of - * classic number functions. - *

- * - *

- * There are two aspects of this package that should be highlighted. The first - * is {@link org.apache.commons.lang3.math.NumberUtils#createNumber(String)}, a - * method which does its best to convert a String into a - * {@link java.lang.Number} object. You have no idea what type of Number it will - * return, so you should call the relevant {@code xxxValue} method when you - * reach the point of needing a number. NumberUtils also has a related - * {@link org.apache.commons.lang3.math.NumberUtils#isCreatable(String)} method. - *

- * - * @since 2.0 - */ -package org.apache.commons.lang3.math; diff --git a/sources/main/java/org/apache/commons/lang3/mutable/Mutable.java b/sources/main/java/org/apache/commons/lang3/mutable/Mutable.java deleted file mode 100644 index 3d28d08d..00000000 --- a/sources/main/java/org/apache/commons/lang3/mutable/Mutable.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.mutable; - -/** - * Provides mutable access to a value. - *

- * {@code Mutable} is used as a generic interface to the implementations in this - * package. - *

- * A typical use case would be to enable a primitive or string to be passed to a - * method and allow that method to effectively change the value of the - * primitive/string. Another use case is to store a frequently changing - * primitive in a collection (for example a total in a map) without needing to - * create new Integer/Long wrapper objects. - * - * @param the type to set and get - * @since 2.1 - */ -public interface Mutable { - - /** - * Gets the value of this mutable. - * - * @return the stored value - */ - T getValue(); - - /** - * Sets the value of this mutable. - * - * @param value the value to store - * @throws NullPointerException if the object is null and null is invalid - * @throws ClassCastException if the type is invalid - */ - void setValue(T value); - -} diff --git a/sources/main/java/org/apache/commons/lang3/mutable/MutableBoolean.java b/sources/main/java/org/apache/commons/lang3/mutable/MutableBoolean.java deleted file mode 100644 index 95301ffc..00000000 --- a/sources/main/java/org/apache/commons/lang3/mutable/MutableBoolean.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.mutable; - -import java.io.Serializable; - -import org.apache.commons.lang3.BooleanUtils; - -/** - * A mutable {@code boolean} wrapper. - *

- * Note that as MutableBoolean does not extend Boolean, it is not treated by - * HString.format as a Boolean parameter. - * - * @see Boolean - * @since 2.2 - */ -public class MutableBoolean implements Mutable, Serializable, Comparable { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = -4830728138360036487L; - - /** The mutable value. */ - private boolean value; - - /** - * Constructs a new MutableBoolean with the default value of false. - */ - public MutableBoolean() { - } - - /** - * Constructs a new MutableBoolean with the specified value. - * - * @param value the initial value to store - */ - public MutableBoolean(final boolean value) { - this.value = value; - } - - /** - * Constructs a new MutableBoolean with the specified value. - * - * @param value the initial value to store, not null - * @throws NullPointerException if the object is null - */ - public MutableBoolean(final Boolean value) { - this.value = value.booleanValue(); - } - - // ----------------------------------------------------------------------- - /** - * Gets the value as a Boolean instance. - * - * @return the value as a Boolean, never null - */ - @Override - public Boolean getValue() { - return Boolean.valueOf(this.value); - } - - /** - * Sets the value. - * - * @param value the value to set - */ - public void setValue(final boolean value) { - this.value = value; - } - - /** - * Sets the value to false. - * - * @since 3.3 - */ - public void setFalse() { - this.value = false; - } - - /** - * Sets the value to true. - * - * @since 3.3 - */ - public void setTrue() { - this.value = true; - } - - /** - * Sets the value from any Boolean instance. - * - * @param value the value to set, not null - * @throws NullPointerException if the object is null - */ - @Override - public void setValue(final Boolean value) { - this.value = value.booleanValue(); - } - - // ----------------------------------------------------------------------- - /** - * Checks if the current value is {@code true}. - * - * @return {@code true} if the current value is {@code true} - * @since 2.5 - */ - public boolean isTrue() { - return value; - } - - /** - * Checks if the current value is {@code false}. - * - * @return {@code true} if the current value is {@code false} - * @since 2.5 - */ - public boolean isFalse() { - return !value; - } - - // ----------------------------------------------------------------------- - /** - * Returns the value of this MutableBoolean as a boolean. - * - * @return the boolean value represented by this object. - */ - public boolean booleanValue() { - return value; - } - - // ----------------------------------------------------------------------- - /** - * Gets this mutable as an instance of Boolean. - * - * @return a Boolean instance containing the value from this mutable, never null - * @since 2.5 - */ - public Boolean toBoolean() { - return Boolean.valueOf(booleanValue()); - } - - // ----------------------------------------------------------------------- - /** - * Compares this object to the specified object. The result is {@code true} if - * and only if the argument is not {@code null} and is an {@code MutableBoolean} - * object that contains the same {@code boolean} value as this object. - * - * @param obj the object to compare with, null returns false - * @return {@code true} if the objects are the same; {@code false} otherwise. - */ - @Override - public boolean equals(final Object obj) { - if (obj instanceof MutableBoolean) { - return value == ((MutableBoolean) obj).booleanValue(); - } - return false; - } - - /** - * Returns a suitable hash code for this mutable. - * - * @return the hash code returned by {@code Boolean.TRUE} or - * {@code Boolean.FALSE} - */ - @Override - public int hashCode() { - return value ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode(); - } - - // ----------------------------------------------------------------------- - /** - * Compares this mutable to another in ascending order. - * - * @param other the other mutable to compare to, not null - * @return negative if this is less, zero if equal, positive if greater where - * false is less than true - */ - @Override - public int compareTo(final MutableBoolean other) { - return BooleanUtils.compare(this.value, other.value); - } - - // ----------------------------------------------------------------------- - /** - * Returns the String value of this mutable. - * - * @return the mutable value as a string - */ - @Override - public String toString() { - return String.valueOf(value); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/mutable/MutableByte.java b/sources/main/java/org/apache/commons/lang3/mutable/MutableByte.java deleted file mode 100644 index 0244b466..00000000 --- a/sources/main/java/org/apache/commons/lang3/mutable/MutableByte.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.mutable; - -import org.apache.commons.lang3.math.NumberUtils; - -/** - * A mutable {@code byte} wrapper. - *

- * Note that as MutableByte does not extend Byte, it is not treated by - * HString.format as a Byte parameter. - * - * @see Byte - * @since 2.1 - */ -public class MutableByte extends Number implements Comparable, Mutable { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = -1585823265L; - - /** The mutable value. */ - private byte value; - - /** - * Constructs a new MutableByte with the default value of zero. - */ - public MutableByte() { - } - - /** - * Constructs a new MutableByte with the specified value. - * - * @param value the initial value to store - */ - public MutableByte(final byte value) { - this.value = value; - } - - /** - * Constructs a new MutableByte with the specified value. - * - * @param value the initial value to store, not null - * @throws NullPointerException if the object is null - */ - public MutableByte(final Number value) { - this.value = value.byteValue(); - } - - /** - * Constructs a new MutableByte parsing the given string. - * - * @param value the string to parse, not null - * @throws NumberFormatException if the string cannot be parsed into a byte - * @since 2.5 - */ - public MutableByte(final String value) { - this.value = Byte.parseByte(value); - } - - // ----------------------------------------------------------------------- - /** - * Gets the value as a Byte instance. - * - * @return the value as a Byte, never null - */ - @Override - public Byte getValue() { - return Byte.valueOf(this.value); - } - - /** - * Sets the value. - * - * @param value the value to set - */ - public void setValue(final byte value) { - this.value = value; - } - - /** - * Sets the value from any Number instance. - * - * @param value the value to set, not null - * @throws NullPointerException if the object is null - */ - @Override - public void setValue(final Number value) { - this.value = value.byteValue(); - } - - // ----------------------------------------------------------------------- - /** - * Increments the value. - * - * @since 2.2 - */ - public void increment() { - value++; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the increment operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was incremented - * @since 3.5 - */ - public byte getAndIncrement() { - final byte last = value; - value++; - return last; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately after the increment operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is incremented - * @since 3.5 - */ - public byte incrementAndGet() { - value++; - return value; - } - - /** - * Decrements the value. - * - * @since 2.2 - */ - public void decrement() { - value--; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the decrement operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was decremented - * @since 3.5 - */ - public byte getAndDecrement() { - final byte last = value; - value--; - return last; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately after the decrement operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is decremented - * @since 3.5 - */ - public byte decrementAndGet() { - value--; - return value; - } - - // ----------------------------------------------------------------------- - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @since 2.2 - */ - public void add(final byte operand) { - this.value += operand; - } - - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void add(final Number operand) { - this.value += operand.byteValue(); - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @since 2.2 - */ - public void subtract(final byte operand) { - this.value -= operand; - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void subtract(final Number operand) { - this.value -= operand.byteValue(); - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public byte addAndGet(final byte operand) { - this.value += operand; - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public byte addAndGet(final Number operand) { - this.value += operand.byteValue(); - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public byte getAndAdd(final byte operand) { - final byte last = value; - this.value += operand; - return last; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public byte getAndAdd(final Number operand) { - final byte last = value; - this.value += operand.byteValue(); - return last; - } - - // ----------------------------------------------------------------------- - // shortValue relies on Number implementation - /** - * Returns the value of this MutableByte as a byte. - * - * @return the numeric value represented by this object after conversion to type - * byte. - */ - @Override - public byte byteValue() { - return value; - } - - /** - * Returns the value of this MutableByte as an int. - * - * @return the numeric value represented by this object after conversion to type - * int. - */ - @Override - public int intValue() { - return value; - } - - /** - * Returns the value of this MutableByte as a long. - * - * @return the numeric value represented by this object after conversion to type - * long. - */ - @Override - public long longValue() { - return value; - } - - /** - * Returns the value of this MutableByte as a float. - * - * @return the numeric value represented by this object after conversion to type - * float. - */ - @Override - public float floatValue() { - return value; - } - - /** - * Returns the value of this MutableByte as a double. - * - * @return the numeric value represented by this object after conversion to type - * double. - */ - @Override - public double doubleValue() { - return value; - } - - // ----------------------------------------------------------------------- - /** - * Gets this mutable as an instance of Byte. - * - * @return a Byte instance containing the value from this mutable - */ - public Byte toByte() { - return Byte.valueOf(byteValue()); - } - - // ----------------------------------------------------------------------- - /** - * Compares this object to the specified object. The result is {@code true} if - * and only if the argument is not {@code null} and is a {@code MutableByte} - * object that contains the same {@code byte} value as this object. - * - * @param obj the object to compare with, null returns false - * @return {@code true} if the objects are the same; {@code false} otherwise. - */ - @Override - public boolean equals(final Object obj) { - if (obj instanceof MutableByte) { - return value == ((MutableByte) obj).byteValue(); - } - return false; - } - - /** - * Returns a suitable hash code for this mutable. - * - * @return a suitable hash code - */ - @Override - public int hashCode() { - return value; - } - - // ----------------------------------------------------------------------- - /** - * Compares this mutable to another in ascending order. - * - * @param other the other mutable to compare to, not null - * @return negative if this is less, zero if equal, positive if greater - */ - @Override - public int compareTo(final MutableByte other) { - return NumberUtils.compare(this.value, other.value); - } - - // ----------------------------------------------------------------------- - /** - * Returns the String value of this mutable. - * - * @return the mutable value as a string - */ - @Override - public String toString() { - return String.valueOf(value); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/mutable/MutableDouble.java b/sources/main/java/org/apache/commons/lang3/mutable/MutableDouble.java deleted file mode 100644 index 1754e360..00000000 --- a/sources/main/java/org/apache/commons/lang3/mutable/MutableDouble.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.mutable; - -/** - * A mutable {@code double} wrapper. - *

- * Note that as MutableDouble does not extend Double, it is not treated by - * HString.format as a Double parameter. - * - * @see Double - * @since 2.1 - */ -public class MutableDouble extends Number implements Comparable, Mutable { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 1587163916L; - - /** The mutable value. */ - private double value; - - /** - * Constructs a new MutableDouble with the default value of zero. - */ - public MutableDouble() { - } - - /** - * Constructs a new MutableDouble with the specified value. - * - * @param value the initial value to store - */ - public MutableDouble(final double value) { - this.value = value; - } - - /** - * Constructs a new MutableDouble with the specified value. - * - * @param value the initial value to store, not null - * @throws NullPointerException if the object is null - */ - public MutableDouble(final Number value) { - this.value = value.doubleValue(); - } - - /** - * Constructs a new MutableDouble parsing the given string. - * - * @param value the string to parse, not null - * @throws NumberFormatException if the string cannot be parsed into a double - * @since 2.5 - */ - public MutableDouble(final String value) { - this.value = Double.parseDouble(value); - } - - // ----------------------------------------------------------------------- - /** - * Gets the value as a Double instance. - * - * @return the value as a Double, never null - */ - @Override - public Double getValue() { - return Double.valueOf(this.value); - } - - /** - * Sets the value. - * - * @param value the value to set - */ - public void setValue(final double value) { - this.value = value; - } - - /** - * Sets the value from any Number instance. - * - * @param value the value to set, not null - * @throws NullPointerException if the object is null - */ - @Override - public void setValue(final Number value) { - this.value = value.doubleValue(); - } - - // ----------------------------------------------------------------------- - /** - * Checks whether the double value is the special NaN value. - * - * @return true if NaN - */ - public boolean isNaN() { - return Double.isNaN(value); - } - - /** - * Checks whether the double value is infinite. - * - * @return true if infinite - */ - public boolean isInfinite() { - return Double.isInfinite(value); - } - - // ----------------------------------------------------------------------- - /** - * Increments the value. - * - * @since 2.2 - */ - public void increment() { - value++; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the increment operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was incremented - * @since 3.5 - */ - public double getAndIncrement() { - final double last = value; - value++; - return last; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately after the increment operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is incremented - * @since 3.5 - */ - public double incrementAndGet() { - value++; - return value; - } - - /** - * Decrements the value. - * - * @since 2.2 - */ - public void decrement() { - value--; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the decrement operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was decremented - * @since 3.5 - */ - public double getAndDecrement() { - final double last = value; - value--; - return last; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately after the decrement operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is decremented - * @since 3.5 - */ - public double decrementAndGet() { - value--; - return value; - } - - // ----------------------------------------------------------------------- - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add - * @since 2.2 - */ - public void add(final double operand) { - this.value += operand; - } - - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void add(final Number operand) { - this.value += operand.doubleValue(); - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @since 2.2 - */ - public void subtract(final double operand) { - this.value -= operand; - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void subtract(final Number operand) { - this.value -= operand.doubleValue(); - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public double addAndGet(final double operand) { - this.value += operand; - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public double addAndGet(final Number operand) { - this.value += operand.doubleValue(); - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public double getAndAdd(final double operand) { - final double last = value; - this.value += operand; - return last; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public double getAndAdd(final Number operand) { - final double last = value; - this.value += operand.doubleValue(); - return last; - } - - // ----------------------------------------------------------------------- - // shortValue and byteValue rely on Number implementation - /** - * Returns the value of this MutableDouble as an int. - * - * @return the numeric value represented by this object after conversion to type - * int. - */ - @Override - public int intValue() { - return (int) value; - } - - /** - * Returns the value of this MutableDouble as a long. - * - * @return the numeric value represented by this object after conversion to type - * long. - */ - @Override - public long longValue() { - return (long) value; - } - - /** - * Returns the value of this MutableDouble as a float. - * - * @return the numeric value represented by this object after conversion to type - * float. - */ - @Override - public float floatValue() { - return (float) value; - } - - /** - * Returns the value of this MutableDouble as a double. - * - * @return the numeric value represented by this object after conversion to type - * double. - */ - @Override - public double doubleValue() { - return value; - } - - // ----------------------------------------------------------------------- - /** - * Gets this mutable as an instance of Double. - * - * @return a Double instance containing the value from this mutable, never null - */ - public Double toDouble() { - return Double.valueOf(doubleValue()); - } - - // ----------------------------------------------------------------------- - /** - * Compares this object against the specified object. The result is {@code true} - * if and only if the argument is not {@code null} and is a {@code Double} - * object that represents a double that has the identical bit pattern to the bit - * pattern of the double represented by this object. For this purpose, two - * {@code double} values are considered to be the same if and only if the method - * {@link Double#doubleToLongBits(double)}returns the same long value when - * applied to each. - *

- * Note that in most cases, for two instances of class {@code Double},{@code d1} - * and {@code d2}, the value of {@code d1.equals(d2)} is {@code true} if and - * only if

- * - *
-	 * d1.doubleValue() == d2.doubleValue()
-	 * 
- * - *
- *

- * also has the value {@code true}. However, there are two exceptions: - *

    - *
  • If {@code d1} and {@code d2} both represent {@code Double.NaN}, then the - * {@code equals} method returns {@code true}, even though - * {@code Double.NaN==Double.NaN} has the value {@code false}. - *
  • If {@code d1} represents {@code +0.0} while {@code d2} represents - * {@code -0.0}, or vice versa, the {@code equal} test has the value - * {@code false}, even though {@code +0.0==-0.0} has the value {@code true}. - * This allows hashtables to operate properly. - *
- * - * @param obj the object to compare with, null returns false - * @return {@code true} if the objects are the same; {@code false} otherwise. - */ - @Override - public boolean equals(final Object obj) { - return obj instanceof MutableDouble - && Double.doubleToLongBits(((MutableDouble) obj).value) == Double.doubleToLongBits(value); - } - - /** - * Returns a suitable hash code for this mutable. - * - * @return a suitable hash code - */ - @Override - public int hashCode() { - final long bits = Double.doubleToLongBits(value); - return (int) (bits ^ bits >>> 32); - } - - // ----------------------------------------------------------------------- - /** - * Compares this mutable to another in ascending order. - * - * @param other the other mutable to compare to, not null - * @return negative if this is less, zero if equal, positive if greater - */ - @Override - public int compareTo(final MutableDouble other) { - return Double.compare(this.value, other.value); - } - - // ----------------------------------------------------------------------- - /** - * Returns the String value of this mutable. - * - * @return the mutable value as a string - */ - @Override - public String toString() { - return String.valueOf(value); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/mutable/MutableFloat.java b/sources/main/java/org/apache/commons/lang3/mutable/MutableFloat.java deleted file mode 100644 index 7315a595..00000000 --- a/sources/main/java/org/apache/commons/lang3/mutable/MutableFloat.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.mutable; - -/** - * A mutable {@code float} wrapper. - *

- * Note that as MutableFloat does not extend Float, it is not treated by - * HString.format as a Float parameter. - * - * @see Float - * @since 2.1 - */ -public class MutableFloat extends Number implements Comparable, Mutable { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 5787169186L; - - /** The mutable value. */ - private float value; - - /** - * Constructs a new MutableFloat with the default value of zero. - */ - public MutableFloat() { - } - - /** - * Constructs a new MutableFloat with the specified value. - * - * @param value the initial value to store - */ - public MutableFloat(final float value) { - this.value = value; - } - - /** - * Constructs a new MutableFloat with the specified value. - * - * @param value the initial value to store, not null - * @throws NullPointerException if the object is null - */ - public MutableFloat(final Number value) { - this.value = value.floatValue(); - } - - /** - * Constructs a new MutableFloat parsing the given string. - * - * @param value the string to parse, not null - * @throws NumberFormatException if the string cannot be parsed into a float - * @since 2.5 - */ - public MutableFloat(final String value) { - this.value = Float.parseFloat(value); - } - - // ----------------------------------------------------------------------- - /** - * Gets the value as a Float instance. - * - * @return the value as a Float, never null - */ - @Override - public Float getValue() { - return Float.valueOf(this.value); - } - - /** - * Sets the value. - * - * @param value the value to set - */ - public void setValue(final float value) { - this.value = value; - } - - /** - * Sets the value from any Number instance. - * - * @param value the value to set, not null - * @throws NullPointerException if the object is null - */ - @Override - public void setValue(final Number value) { - this.value = value.floatValue(); - } - - // ----------------------------------------------------------------------- - /** - * Checks whether the float value is the special NaN value. - * - * @return true if NaN - */ - public boolean isNaN() { - return Float.isNaN(value); - } - - /** - * Checks whether the float value is infinite. - * - * @return true if infinite - */ - public boolean isInfinite() { - return Float.isInfinite(value); - } - - // ----------------------------------------------------------------------- - /** - * Increments the value. - * - * @since 2.2 - */ - public void increment() { - value++; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the increment operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was incremented - * @since 3.5 - */ - public float getAndIncrement() { - final float last = value; - value++; - return last; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately after the increment operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is incremented - * @since 3.5 - */ - public float incrementAndGet() { - value++; - return value; - } - - /** - * Decrements the value. - * - * @since 2.2 - */ - public void decrement() { - value--; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the decrement operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was decremented - * @since 3.5 - */ - public float getAndDecrement() { - final float last = value; - value--; - return last; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately after the decrement operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is decremented - * @since 3.5 - */ - public float decrementAndGet() { - value--; - return value; - } - - // ----------------------------------------------------------------------- - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @since 2.2 - */ - public void add(final float operand) { - this.value += operand; - } - - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void add(final Number operand) { - this.value += operand.floatValue(); - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract - * @since 2.2 - */ - public void subtract(final float operand) { - this.value -= operand; - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void subtract(final Number operand) { - this.value -= operand.floatValue(); - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public float addAndGet(final float operand) { - this.value += operand; - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public float addAndGet(final Number operand) { - this.value += operand.floatValue(); - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public float getAndAdd(final float operand) { - final float last = value; - this.value += operand; - return last; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public float getAndAdd(final Number operand) { - final float last = value; - this.value += operand.floatValue(); - return last; - } - - // ----------------------------------------------------------------------- - // shortValue and byteValue rely on Number implementation - /** - * Returns the value of this MutableFloat as an int. - * - * @return the numeric value represented by this object after conversion to type - * int. - */ - @Override - public int intValue() { - return (int) value; - } - - /** - * Returns the value of this MutableFloat as a long. - * - * @return the numeric value represented by this object after conversion to type - * long. - */ - @Override - public long longValue() { - return (long) value; - } - - /** - * Returns the value of this MutableFloat as a float. - * - * @return the numeric value represented by this object after conversion to type - * float. - */ - @Override - public float floatValue() { - return value; - } - - /** - * Returns the value of this MutableFloat as a double. - * - * @return the numeric value represented by this object after conversion to type - * double. - */ - @Override - public double doubleValue() { - return value; - } - - // ----------------------------------------------------------------------- - /** - * Gets this mutable as an instance of Float. - * - * @return a Float instance containing the value from this mutable, never null - */ - public Float toFloat() { - return Float.valueOf(floatValue()); - } - - // ----------------------------------------------------------------------- - /** - * Compares this object against some other object. The result is {@code true} if - * and only if the argument is not {@code null} and is a {@code Float} object - * that represents a {@code float} that has the identical bit pattern to the bit - * pattern of the {@code float} represented by this object. For this purpose, - * two float values are considered to be the same if and only if the method - * {@link Float#floatToIntBits(float)}returns the same int value when applied to - * each. - *

- * Note that in most cases, for two instances of class {@code Float},{@code f1} - * and {@code f2}, the value of {@code f1.equals(f2)} is {@code true} if and - * only if

- * - *
-	 * f1.floatValue() == f2.floatValue()
-	 * 
- * - *
- *

- * also has the value {@code true}. However, there are two exceptions: - *

    - *
  • If {@code f1} and {@code f2} both represent {@code Float.NaN}, then the - * {@code equals} method returns {@code true}, even though - * {@code Float.NaN==Float.NaN} has the value {@code false}. - *
  • If {@code f1} represents {@code +0.0f} while {@code f2} represents - * {@code -0.0f}, or vice versa, the {@code equal} test has the value - * {@code false}, even though {@code 0.0f==-0.0f} has the value {@code true}. - *
- * This definition allows hashtables to operate properly. - * - * @param obj the object to compare with, null returns false - * @return {@code true} if the objects are the same; {@code false} otherwise. - * @see java.lang.Float#floatToIntBits(float) - */ - @Override - public boolean equals(final Object obj) { - return obj instanceof MutableFloat - && Float.floatToIntBits(((MutableFloat) obj).value) == Float.floatToIntBits(value); - } - - /** - * Returns a suitable hash code for this mutable. - * - * @return a suitable hash code - */ - @Override - public int hashCode() { - return Float.floatToIntBits(value); - } - - // ----------------------------------------------------------------------- - /** - * Compares this mutable to another in ascending order. - * - * @param other the other mutable to compare to, not null - * @return negative if this is less, zero if equal, positive if greater - */ - @Override - public int compareTo(final MutableFloat other) { - return Float.compare(this.value, other.value); - } - - // ----------------------------------------------------------------------- - /** - * Returns the String value of this mutable. - * - * @return the mutable value as a string - */ - @Override - public String toString() { - return String.valueOf(value); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/mutable/MutableInt.java b/sources/main/java/org/apache/commons/lang3/mutable/MutableInt.java deleted file mode 100644 index 90c2d8b2..00000000 --- a/sources/main/java/org/apache/commons/lang3/mutable/MutableInt.java +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.mutable; - -import org.apache.commons.lang3.math.NumberUtils; - -/** - * A mutable {@code int} wrapper. - *

- * Note that as MutableInt does not extend Integer, it is not treated by - * HString.format as an Integer parameter. - * - * @see Integer - * @since 2.1 - */ -public class MutableInt extends Number implements Comparable, Mutable { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 512176391864L; - - /** The mutable value. */ - private int value; - - /** - * Constructs a new MutableInt with the default value of zero. - */ - public MutableInt() { - } - - /** - * Constructs a new MutableInt with the specified value. - * - * @param value the initial value to store - */ - public MutableInt(final int value) { - this.value = value; - } - - /** - * Constructs a new MutableInt with the specified value. - * - * @param value the initial value to store, not null - * @throws NullPointerException if the object is null - */ - public MutableInt(final Number value) { - this.value = value.intValue(); - } - - /** - * Constructs a new MutableInt parsing the given string. - * - * @param value the string to parse, not null - * @throws NumberFormatException if the string cannot be parsed into an int - * @since 2.5 - */ - public MutableInt(final String value) { - this.value = Integer.parseInt(value); - } - - // ----------------------------------------------------------------------- - /** - * Gets the value as a Integer instance. - * - * @return the value as a Integer, never null - */ - @Override - public Integer getValue() { - return Integer.valueOf(this.value); - } - - /** - * Sets the value. - * - * @param value the value to set - */ - public void setValue(final int value) { - this.value = value; - } - - /** - * Sets the value from any Number instance. - * - * @param value the value to set, not null - * @throws NullPointerException if the object is null - */ - @Override - public void setValue(final Number value) { - this.value = value.intValue(); - } - - // ----------------------------------------------------------------------- - /** - * Increments the value. - * - * @since 2.2 - */ - public void increment() { - value++; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the increment operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was incremented - * @since 3.5 - */ - public int getAndIncrement() { - final int last = value; - value++; - return last; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately after the increment operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is incremented - * @since 3.5 - */ - public int incrementAndGet() { - value++; - return value; - } - - /** - * Decrements the value. - * - * @since 2.2 - */ - public void decrement() { - value--; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the decrement operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was decremented - * @since 3.5 - */ - public int getAndDecrement() { - final int last = value; - value--; - return last; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately after the decrement operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is decremented - * @since 3.5 - */ - public int decrementAndGet() { - value--; - return value; - } - - // ----------------------------------------------------------------------- - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @since 2.2 - */ - public void add(final int operand) { - this.value += operand; - } - - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void add(final Number operand) { - this.value += operand.intValue(); - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @since 2.2 - */ - public void subtract(final int operand) { - this.value -= operand; - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void subtract(final Number operand) { - this.value -= operand.intValue(); - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public int addAndGet(final int operand) { - this.value += operand; - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public int addAndGet(final Number operand) { - this.value += operand.intValue(); - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public int getAndAdd(final int operand) { - final int last = value; - this.value += operand; - return last; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public int getAndAdd(final Number operand) { - final int last = value; - this.value += operand.intValue(); - return last; - } - - // ----------------------------------------------------------------------- - // shortValue and byteValue rely on Number implementation - /** - * Returns the value of this MutableInt as an int. - * - * @return the numeric value represented by this object after conversion to type - * int. - */ - @Override - public int intValue() { - return value; - } - - /** - * Returns the value of this MutableInt as a long. - * - * @return the numeric value represented by this object after conversion to type - * long. - */ - @Override - public long longValue() { - return value; - } - - /** - * Returns the value of this MutableInt as a float. - * - * @return the numeric value represented by this object after conversion to type - * float. - */ - @Override - public float floatValue() { - return value; - } - - /** - * Returns the value of this MutableInt as a double. - * - * @return the numeric value represented by this object after conversion to type - * double. - */ - @Override - public double doubleValue() { - return value; - } - - // ----------------------------------------------------------------------- - /** - * Gets this mutable as an instance of Integer. - * - * @return a Integer instance containing the value from this mutable, never null - */ - public Integer toInteger() { - return Integer.valueOf(intValue()); - } - - // ----------------------------------------------------------------------- - /** - * Compares this object to the specified object. The result is {@code true} if - * and only if the argument is not {@code null} and is a {@code MutableInt} - * object that contains the same {@code int} value as this object. - * - * @param obj the object to compare with, null returns false - * @return {@code true} if the objects are the same; {@code false} otherwise. - */ - @Override - public boolean equals(final Object obj) { - if (obj instanceof MutableInt) { - return value == ((MutableInt) obj).intValue(); - } - return false; - } - - /** - * Returns a suitable hash code for this mutable. - * - * @return a suitable hash code - */ - @Override - public int hashCode() { - return value; - } - - // ----------------------------------------------------------------------- - /** - * Compares this mutable to another in ascending order. - * - * @param other the other mutable to compare to, not null - * @return negative if this is less, zero if equal, positive if greater - */ - @Override - public int compareTo(final MutableInt other) { - return NumberUtils.compare(this.value, other.value); - } - - // ----------------------------------------------------------------------- - /** - * Returns the String value of this mutable. - * - * @return the mutable value as a string - */ - @Override - public String toString() { - return String.valueOf(value); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/mutable/MutableLong.java b/sources/main/java/org/apache/commons/lang3/mutable/MutableLong.java deleted file mode 100644 index 7b8ae315..00000000 --- a/sources/main/java/org/apache/commons/lang3/mutable/MutableLong.java +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.mutable; - -import org.apache.commons.lang3.math.NumberUtils; - -/** - * A mutable {@code long} wrapper. - *

- * Note that as MutableLong does not extend Long, it is not treated by - * HString.format as a Long parameter. - * - * @see Long - * @since 2.1 - */ -public class MutableLong extends Number implements Comparable, Mutable { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 62986528375L; - - /** The mutable value. */ - private long value; - - /** - * Constructs a new MutableLong with the default value of zero. - */ - public MutableLong() { - } - - /** - * Constructs a new MutableLong with the specified value. - * - * @param value the initial value to store - */ - public MutableLong(final long value) { - this.value = value; - } - - /** - * Constructs a new MutableLong with the specified value. - * - * @param value the initial value to store, not null - * @throws NullPointerException if the object is null - */ - public MutableLong(final Number value) { - this.value = value.longValue(); - } - - /** - * Constructs a new MutableLong parsing the given string. - * - * @param value the string to parse, not null - * @throws NumberFormatException if the string cannot be parsed into a long - * @since 2.5 - */ - public MutableLong(final String value) { - this.value = Long.parseLong(value); - } - - // ----------------------------------------------------------------------- - /** - * Gets the value as a Long instance. - * - * @return the value as a Long, never null - */ - @Override - public Long getValue() { - return Long.valueOf(this.value); - } - - /** - * Sets the value. - * - * @param value the value to set - */ - public void setValue(final long value) { - this.value = value; - } - - /** - * Sets the value from any Number instance. - * - * @param value the value to set, not null - * @throws NullPointerException if the object is null - */ - @Override - public void setValue(final Number value) { - this.value = value.longValue(); - } - - // ----------------------------------------------------------------------- - /** - * Increments the value. - * - * @since 2.2 - */ - public void increment() { - value++; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the increment operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was incremented - * @since 3.5 - */ - public long getAndIncrement() { - final long last = value; - value++; - return last; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately after the increment operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is incremented - * @since 3.5 - */ - public long incrementAndGet() { - value++; - return value; - } - - /** - * Decrements the value. - * - * @since 2.2 - */ - public void decrement() { - value--; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the decrement operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was decremented - * @since 3.5 - */ - public long getAndDecrement() { - final long last = value; - value--; - return last; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately after the decrement operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is decremented - * @since 3.5 - */ - public long decrementAndGet() { - value--; - return value; - } - - // ----------------------------------------------------------------------- - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @since 2.2 - */ - public void add(final long operand) { - this.value += operand; - } - - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void add(final Number operand) { - this.value += operand.longValue(); - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @since 2.2 - */ - public void subtract(final long operand) { - this.value -= operand; - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void subtract(final Number operand) { - this.value -= operand.longValue(); - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public long addAndGet(final long operand) { - this.value += operand; - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public long addAndGet(final Number operand) { - this.value += operand.longValue(); - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public long getAndAdd(final long operand) { - final long last = value; - this.value += operand; - return last; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public long getAndAdd(final Number operand) { - final long last = value; - this.value += operand.longValue(); - return last; - } - - // ----------------------------------------------------------------------- - // shortValue and byteValue rely on Number implementation - /** - * Returns the value of this MutableLong as an int. - * - * @return the numeric value represented by this object after conversion to type - * int. - */ - @Override - public int intValue() { - return (int) value; - } - - /** - * Returns the value of this MutableLong as a long. - * - * @return the numeric value represented by this object after conversion to type - * long. - */ - @Override - public long longValue() { - return value; - } - - /** - * Returns the value of this MutableLong as a float. - * - * @return the numeric value represented by this object after conversion to type - * float. - */ - @Override - public float floatValue() { - return value; - } - - /** - * Returns the value of this MutableLong as a double. - * - * @return the numeric value represented by this object after conversion to type - * double. - */ - @Override - public double doubleValue() { - return value; - } - - // ----------------------------------------------------------------------- - /** - * Gets this mutable as an instance of Long. - * - * @return a Long instance containing the value from this mutable, never null - */ - public Long toLong() { - return Long.valueOf(longValue()); - } - - // ----------------------------------------------------------------------- - /** - * Compares this object to the specified object. The result is {@code true} if - * and only if the argument is not {@code null} and is a {@code MutableLong} - * object that contains the same {@code long} value as this object. - * - * @param obj the object to compare with, null returns false - * @return {@code true} if the objects are the same; {@code false} otherwise. - */ - @Override - public boolean equals(final Object obj) { - if (obj instanceof MutableLong) { - return value == ((MutableLong) obj).longValue(); - } - return false; - } - - /** - * Returns a suitable hash code for this mutable. - * - * @return a suitable hash code - */ - @Override - public int hashCode() { - return (int) (value ^ (value >>> 32)); - } - - // ----------------------------------------------------------------------- - /** - * Compares this mutable to another in ascending order. - * - * @param other the other mutable to compare to, not null - * @return negative if this is less, zero if equal, positive if greater - */ - @Override - public int compareTo(final MutableLong other) { - return NumberUtils.compare(this.value, other.value); - } - - // ----------------------------------------------------------------------- - /** - * Returns the String value of this mutable. - * - * @return the mutable value as a string - */ - @Override - public String toString() { - return String.valueOf(value); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/mutable/MutableObject.java b/sources/main/java/org/apache/commons/lang3/mutable/MutableObject.java deleted file mode 100644 index 08f8f42b..00000000 --- a/sources/main/java/org/apache/commons/lang3/mutable/MutableObject.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.lang3.mutable; - -import java.io.Serializable; - -/** - * A mutable {@code Object} wrapper. - * - * @param the type to set and get - * @since 2.1 - */ -public class MutableObject implements Mutable, Serializable { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 86241875189L; - - /** The mutable value. */ - private T value; - - /** - * Constructs a new MutableObject with the default value of {@code null}. - */ - public MutableObject() { - } - - /** - * Constructs a new MutableObject with the specified value. - * - * @param value the initial value to store - */ - public MutableObject(final T value) { - this.value = value; - } - - // ----------------------------------------------------------------------- - /** - * Gets the value. - * - * @return the value, may be null - */ - @Override - public T getValue() { - return this.value; - } - - /** - * Sets the value. - * - * @param value the value to set - */ - @Override - public void setValue(final T value) { - this.value = value; - } - - // ----------------------------------------------------------------------- - /** - *

- * Compares this object against the specified object. The result is {@code true} - * if and only if the argument is not {@code null} and is a - * {@code MutableObject} object that contains the same {@code T} value as this - * object. - *

- * - * @param obj the object to compare with, {@code null} returns {@code false} - * @return {@code true} if the objects are the same; {@code true} if the objects - * have equivalent {@code value} fields; {@code false} otherwise. - */ - @Override - public boolean equals(final Object obj) { - if (obj == null) { - return false; - } - if (this == obj) { - return true; - } - if (this.getClass() == obj.getClass()) { - final MutableObject that = (MutableObject) obj; - return this.value.equals(that.value); - } - return false; - } - - /** - * Returns the value's hash code or {@code 0} if the value is {@code null}. - * - * @return the value's hash code or {@code 0} if the value is {@code null}. - */ - @Override - public int hashCode() { - return value == null ? 0 : value.hashCode(); - } - - // ----------------------------------------------------------------------- - /** - * Returns the String value of this mutable. - * - * @return the mutable value as a string - */ - @Override - public String toString() { - return value == null ? "null" : value.toString(); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/mutable/MutableShort.java b/sources/main/java/org/apache/commons/lang3/mutable/MutableShort.java deleted file mode 100644 index 9ccf0b64..00000000 --- a/sources/main/java/org/apache/commons/lang3/mutable/MutableShort.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.mutable; - -import org.apache.commons.lang3.math.NumberUtils; - -/** - * A mutable {@code short} wrapper. - *

- * Note that as MutableShort does not extend Short, it is not treated by - * HString.format as a Short parameter. - * - * @see Short - * @since 2.1 - */ -public class MutableShort extends Number implements Comparable, Mutable { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = -2135791679L; - - /** The mutable value. */ - private short value; - - /** - * Constructs a new MutableShort with the default value of zero. - */ - public MutableShort() { - } - - /** - * Constructs a new MutableShort with the specified value. - * - * @param value the initial value to store - */ - public MutableShort(final short value) { - this.value = value; - } - - /** - * Constructs a new MutableShort with the specified value. - * - * @param value the initial value to store, not null - * @throws NullPointerException if the object is null - */ - public MutableShort(final Number value) { - this.value = value.shortValue(); - } - - /** - * Constructs a new MutableShort parsing the given string. - * - * @param value the string to parse, not null - * @throws NumberFormatException if the string cannot be parsed into a short - * @since 2.5 - */ - public MutableShort(final String value) { - this.value = Short.parseShort(value); - } - - // ----------------------------------------------------------------------- - /** - * Gets the value as a Short instance. - * - * @return the value as a Short, never null - */ - @Override - public Short getValue() { - return Short.valueOf(this.value); - } - - /** - * Sets the value. - * - * @param value the value to set - */ - public void setValue(final short value) { - this.value = value; - } - - /** - * Sets the value from any Number instance. - * - * @param value the value to set, not null - * @throws NullPointerException if the object is null - */ - @Override - public void setValue(final Number value) { - this.value = value.shortValue(); - } - - // ----------------------------------------------------------------------- - /** - * Increments the value. - * - * @since 2.2 - */ - public void increment() { - value++; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the increment operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was incremented - * @since 3.5 - */ - public short getAndIncrement() { - final short last = value; - value++; - return last; - } - - /** - * Increments this instance's value by 1; this method returns the value - * associated with the instance immediately after the increment operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is incremented - * @since 3.5 - */ - public short incrementAndGet() { - value++; - return value; - } - - /** - * Decrements the value. - * - * @since 2.2 - */ - public void decrement() { - value--; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately prior to the decrement operation. - * This method is not thread safe. - * - * @return the value associated with the instance before it was decremented - * @since 3.5 - */ - public short getAndDecrement() { - final short last = value; - value--; - return last; - } - - /** - * Decrements this instance's value by 1; this method returns the value - * associated with the instance immediately after the decrement operation. This - * method is not thread safe. - * - * @return the value associated with the instance after it is decremented - * @since 3.5 - */ - public short decrementAndGet() { - value--; - return value; - } - - // ----------------------------------------------------------------------- - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @since 2.2 - */ - public void add(final short operand) { - this.value += operand; - } - - /** - * Adds a value to the value of this instance. - * - * @param operand the value to add, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void add(final Number operand) { - this.value += operand.shortValue(); - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @since 2.2 - */ - public void subtract(final short operand) { - this.value -= operand; - } - - /** - * Subtracts a value from the value of this instance. - * - * @param operand the value to subtract, not null - * @throws NullPointerException if the object is null - * @since 2.2 - */ - public void subtract(final Number operand) { - this.value -= operand.shortValue(); - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public short addAndGet(final short operand) { - this.value += operand; - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately after the addition operation. - * This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance after adding the operand - * @since 3.5 - */ - public short addAndGet(final Number operand) { - this.value += operand.shortValue(); - return value; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public short getAndAdd(final short operand) { - final short last = value; - this.value += operand; - return last; - } - - /** - * Increments this instance's value by {@code operand}; this method returns the - * value associated with the instance immediately prior to the addition - * operation. This method is not thread safe. - * - * @param operand the quantity to add, not null - * @throws NullPointerException if {@code operand} is null - * @return the value associated with this instance immediately before the - * operand was added - * @since 3.5 - */ - public short getAndAdd(final Number operand) { - final short last = value; - this.value += operand.shortValue(); - return last; - } - - // ----------------------------------------------------------------------- - // byteValue relies on Number implementation - /** - * Returns the value of this MutableShort as a short. - * - * @return the numeric value represented by this object after conversion to type - * short. - */ - @Override - public short shortValue() { - return value; - } - - /** - * Returns the value of this MutableShort as an int. - * - * @return the numeric value represented by this object after conversion to type - * int. - */ - @Override - public int intValue() { - return value; - } - - /** - * Returns the value of this MutableShort as a long. - * - * @return the numeric value represented by this object after conversion to type - * long. - */ - @Override - public long longValue() { - return value; - } - - /** - * Returns the value of this MutableShort as a float. - * - * @return the numeric value represented by this object after conversion to type - * float. - */ - @Override - public float floatValue() { - return value; - } - - /** - * Returns the value of this MutableShort as a double. - * - * @return the numeric value represented by this object after conversion to type - * double. - */ - @Override - public double doubleValue() { - return value; - } - - // ----------------------------------------------------------------------- - /** - * Gets this mutable as an instance of Short. - * - * @return a Short instance containing the value from this mutable, never null - */ - public Short toShort() { - return Short.valueOf(shortValue()); - } - - // ----------------------------------------------------------------------- - /** - * Compares this object to the specified object. The result is {@code true} if - * and only if the argument is not {@code null} and is a {@code MutableShort} - * object that contains the same {@code short} value as this object. - * - * @param obj the object to compare with, null returns false - * @return {@code true} if the objects are the same; {@code false} otherwise. - */ - @Override - public boolean equals(final Object obj) { - if (obj instanceof MutableShort) { - return value == ((MutableShort) obj).shortValue(); - } - return false; - } - - /** - * Returns a suitable hash code for this mutable. - * - * @return a suitable hash code - */ - @Override - public int hashCode() { - return value; - } - - // ----------------------------------------------------------------------- - /** - * Compares this mutable to another in ascending order. - * - * @param other the other mutable to compare to, not null - * @return negative if this is less, zero if equal, positive if greater - */ - @Override - public int compareTo(final MutableShort other) { - return NumberUtils.compare(this.value, other.value); - } - - // ----------------------------------------------------------------------- - /** - * Returns the String value of this mutable. - * - * @return the mutable value as a string - */ - @Override - public String toString() { - return String.valueOf(value); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/mutable/package-info.java b/sources/main/java/org/apache/commons/lang3/mutable/package-info.java deleted file mode 100644 index f7519a6d..00000000 --- a/sources/main/java/org/apache/commons/lang3/mutable/package-info.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - *

- * Provides typed mutable wrappers to primitive values and Object. These - * wrappers are similar to the wrappers provided by the Java API, but allow the - * wrapped value to be changed without needing to create a separate wrapper - * object. These classes are not thread-safe. - *

- * - * @since 2.1 - */ -package org.apache.commons.lang3.mutable; diff --git a/sources/main/java/org/apache/commons/lang3/package-info.java b/sources/main/java/org/apache/commons/lang3/package-info.java deleted file mode 100644 index 2882d037..00000000 --- a/sources/main/java/org/apache/commons/lang3/package-info.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - *

- * Provides highly reusable static utility methods, chiefly concerned with - * adding value to the {@link java.lang} classes. Most of these classes are - * immutable and thus thread-safe. However - * {@link org.apache.commons.lang3.CharSet} is not currently guaranteed - * thread-safe under all circumstances. - *

- * - *

- * The top level package contains various Utils classes, whilst there are - * various subpackages including {@link org.apache.commons.lang3.math}, - * {@link org.apache.commons.lang3.concurrent} and - * {@link org.apache.commons.lang3.builder}. Using the Utils classes is - * generally simplicity itself. They are the equivalent of global functions in - * another language, a collection of stand-alone, thread-safe, static methods. - * In contrast, subpackages may contain interfaces which may have to be - * implemented or classes which may need to be extended to get the full - * functionality from the code. They may, however, contain more global-like - * functions. - *

- * - *

- * Lang 3.0 requires JDK 1.5+, since Lang 3.2 it requires JDK 6+; The legacy - * release 2.6 requires JDK 1.2+. In both cases you can find features of later - * JDKs being maintained by us and likely to be removed or modified in favour of - * the JDK in the next major version. Note that Lang 3.0 uses a different - * package than its predecessors, allowing it to be used at the same time as an - * earlier version. - *

- * - *

- * You will find deprecated methods as you stroll through the Lang - * documentation. These are removed in the next major version. - *

- * - *

- * All util classes contain empty public constructors with warnings not to use. - * This may seem an odd thing to do, but it allows tools like Velocity to access - * the class as if it were a bean. In other words, yes we know about private - * constructors and have chosen not to use them. - *

- * - *

String manipulation - StringUtils, StringEscapeUtils, - * RandomStringUtils

- * - *

- * Lang has a series of String utilities. The first is - * {@link org.apache.commons.lang3.StringUtils}, oodles and oodles of functions - * which tweak, transform, squeeze and cuddle {@link java.lang.String - * java.lang.Strings}. In addition to StringUtils, there are a series of other - * String manipulating classes; - * {@link org.apache.commons.lang3.RandomStringUtils} and - * {@link org.apache.commons.lang3.StringEscapeUtils StringEscapeUtils}. - * RandomStringUtils speaks for itself. It's provides ways in which to generate - * pieces of text, such as might be used for default passwords. - * StringEscapeUtils contains methods to escape and unescape Java, JavaScript, - * JSON, HTML and XML. - *

- * - *

- * These are ideal classes to start using if you're looking to get into Lang. - * StringUtils' {@link org.apache.commons.lang3.StringUtils#capitalize(String)}, - * {@link org.apache.commons.lang3.StringUtils#substringBetween(String, String)}/{@link org.apache.commons.lang3.StringUtils#substringBefore(String, String) - * Before}/{@link org.apache.commons.lang3.StringUtils#substringAfter(String, String) - * After}, {@link org.apache.commons.lang3.StringUtils#split(String)} and - * {@link org.apache.commons.lang3.StringUtils#join(Object[])} are good methods - * to begin with. - *

- * - *

Character handling - CharSetUtils, CharSet, CharRange, CharUtils

- * - *

- * In addition to dealing with Strings, it's also important to deal with chars - * and Characters. {@link org.apache.commons.lang3.CharUtils} exists for this - * purpose, while {@link org.apache.commons.lang3.CharSetUtils} exists for - * set-manipulation of Strings. Be careful, although CharSetUtils takes an - * argument of type String, it is only as a set of characters. For example, - * {@code CharSetUtils.delete("testtest", "tr")} will remove all t's and all r's - * from the String, not just the String "tr". - *

- * - *

- * {@link org.apache.commons.lang3.CharRange} and - * {@link org.apache.commons.lang3.CharSet} are both used internally by - * CharSetUtils, and will probably rarely be used. - *

- * - *

JVM interaction - SystemUtils, CharEncoding

- * - *

- * SystemUtils is a simple little class which makes it easy to find out - * information about which platform you are on. For some, this is a necessary - * evil. It was never something I expected to use myself until I was trying to - * ensure that Commons Lang itself compiled under JDK 1.2. Having pushed out a - * few JDK 1.3 bits that had slipped in ({@code Collections.EMPTY_MAP} is a - * classic offender), I then found that one of the Unit Tests was dying - * mysteriously under JDK 1.2, but ran fine under JDK 1.3. There was no obvious - * solution and I needed to move onwards, so the simple solution was to wrap - * that particular test in a - * if (SystemUtils.isJavaVersionAtLeast(1.3f)) {, make a note and - * move on. - *

- * - *

- * The {@link org.apache.commons.lang3.CharEncoding} class is also used to - * interact with the Java environment and may be used to see which character - * encodings are supported in a particular environment. - *

- * - *

Serialization - SerializationUtils, SerializationException

- * - *

- * Serialization doesn't have to be that hard! A simple util class can take away - * the pain, plus it provides a method to clone an object by unserializing and - * reserializing, an old Java trick. - *

- * - *

Assorted functions - ObjectUtils, ClassUtils, ArrayUtils, - * BooleanUtils

- * - *

- * Would you believe it, {@link org.apache.commons.lang3.ObjectUtils} contains - * handy functions for Objects, mainly null-safe implementations of the methods - * on {@link java.lang.Object}. - *

- * - *

- * {@link org.apache.commons.lang3.ClassUtils} is largely a set of helper - * methods for reflection. Of special note are the comparators hidden away in - * ClassUtils, useful for sorting Class and Package objects by name; however - * they merely sort alphabetically and don't understand the common habit of - * sorting {@code java} and {@code javax} first. - *

- * - *

- * Next up, {@link org.apache.commons.lang3.ArrayUtils}. This is a big one with - * many methods and many overloads of these methods so it is probably worth an - * in depth look here. Before we begin, assume that every method mentioned is - * overloaded for all the primitives and for Object. Also, the short-hand 'xxx' - * implies a generic primitive type, but usually also includes Object. - *

- * - *
    - *
  • ArrayUtils provides singleton empty arrays for all the basic types. These - * will largely be of use in the Collections API with its toArray methods, but - * also will be of use with methods which want to return an empty array on - * error.
  • - *
  • {@code add(xxx[], xxx)} will add a primitive type to an array, resizing - * the array as you'd expect. Object is also supported.
  • - *
  • {@code clone(xxx[])} clones a primitive or Object array.
  • - *
  • {@code contains(xxx[], xxx)} searches for a primitive or Object in a - * primitive or Object array.
  • - *
  • {@code getLength(Object)} returns the length of any array or an - * IllegalArgumentException if the parameter is not an array. - * {@code hashCode(Object)}, {@code equals(Object, Object)}, - * {@code toString(Object)}
  • - *
  • {@code indexOf(xxx[], xxx)} and {@code indexOf(xxx[], xxx, int)} are - * copies of the classic String methods, but this time for primitive/Object - * arrays. In addition, a lastIndexOf set of methods exists.
  • - *
  • {@code isEmpty(xxx[])} lets you know if an array is zero-sized or null. - *
  • - *
  • {@code isSameLength(xxx[], xxx[])} returns true if the arrays are the - * same length.
  • - *
  • Along side the add methods, there are also remove methods of two types. - * The first type remove the value at an index, {@code remove(xxx[], int)}, - * while the second type remove the first value from the array, - * {@code remove(xxx[], xxx)}.
  • - *
  • Nearing the end now. The {@code reverse(xxx[])} method turns an array - * around.
  • - *
  • The {@code subarray(xxx[], int, int)} method splices an array out of a - * larger array.
  • - *
  • Primitive to primitive wrapper conversion is handled by the - * {@code toObject(xxx[])} and {@code toPrimitive(Xxx[])} methods.
  • - *
- * - *

- * Lastly, {@link org.apache.commons.lang3.ArrayUtils#toMap(Object[])} is worthy - * of special note. It is not a heavily overloaded method for working with - * arrays, but a simple way to create Maps from literals. - *

- * - *

Using toMap

- * - *
- * 
- * Map colorMap = ArrayUtils.toMap(new String[][] {{
- *   {"RED", "#FF0000"},
- *   {"GREEN", "#00FF00"},
- *   {"BLUE", "#0000FF"}
- * });
- * 
- * 
- * - *

- * Our final util class is {@link org.apache.commons.lang3.BooleanUtils}. It - * contains various Boolean acting methods, probably of most interest is the - * {@link org.apache.commons.lang3.BooleanUtils#toBoolean(String)} method which - * turns various positive/negative Strings into a Boolean object, and not just - * true/false as with Boolean.valueOf. - *

- * - *

Flotsam - BitField, Validate

- *

- * On reaching the end of our package, we are left with a couple of classes that - * haven't fit any of the topics so far. - *

- *

- * The {@link org.apache.commons.lang3.BitField} class provides a wrapper class - * around the classic bitmask integer, whilst the - * {@link org.apache.commons.lang3.Validate} class may be used for assertions - * (remember, we support Java 1.2). - *

- * - * @since 1.0 - */ -package org.apache.commons.lang3; diff --git a/sources/main/java/org/apache/commons/lang3/stream/Streams.java b/sources/main/java/org/apache/commons/lang3/stream/Streams.java deleted file mode 100644 index 497fd800..00000000 --- a/sources/main/java/org/apache/commons/lang3/stream/Streams.java +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.stream; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collector; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.commons.lang3.function.Failable; -import org.apache.commons.lang3.function.FailableConsumer; -import org.apache.commons.lang3.function.FailableFunction; -import org.apache.commons.lang3.function.FailablePredicate; - -/** - * Provides utility functions, and classes for working with the - * {@code java.util.stream} package, or more generally, with Java 8 lambdas. - * More specifically, it attempts to address the fact that lambdas are supposed - * not to throw Exceptions, at least not checked Exceptions, AKA instances of - * {@link Exception}. This enforces the use of constructs like - * - *
- * Consumer<java.lang.reflect.Method> consumer = m -> {
- * 	try {
- * 		m.invoke(o, args);
- * 	} catch (Throwable t) {
- * 		throw Failable.rethrow(t);
- * 	}
- * };
- * stream.forEach(consumer);
- * 
- * - * Using a {@link FailableStream}, this can be rewritten as follows: - * - *
- * Streams.failable(stream).forEach((m) -> m.invoke(o, args));
- * 
- * - * Obviously, the second version is much more concise and the spirit of Lambda - * expressions is met better than in the first version. - * - * @see Stream - * @see Failable - * @since 3.11 - */ -public class Streams { - - /** - * A Collector type for arrays. - * - * @param The array type. - */ - public static class ArrayCollector implements Collector, O[]> { - private static final Set characteristics = Collections.emptySet(); - private final Class elementType; - - /** - * Constructs a new instance for the given element type. - * - * @param elementType The element type. - */ - public ArrayCollector(final Class elementType) { - this.elementType = elementType; - } - - @Override - public BiConsumer, O> accumulator() { - return List::add; - } - - @Override - public Set characteristics() { - return characteristics; - } - - @Override - public BinaryOperator> combiner() { - return (left, right) -> { - left.addAll(right); - return left; - }; - } - - @Override - public Function, O[]> finisher() { - return list -> { - @SuppressWarnings("unchecked") - final O[] array = (O[]) Array.newInstance(elementType, list.size()); - return list.toArray(array); - }; - } - - @Override - public Supplier> supplier() { - return ArrayList::new; - } - } - - /** - * A reduced, and simplified version of a {@link Stream} with failable method - * signatures. - * - * @param The streams element type. - */ - public static class FailableStream { - - private Stream stream; - private boolean terminated; - - /** - * Constructs a new instance with the given {@code stream}. - * - * @param stream The stream. - */ - public FailableStream(final Stream stream) { - this.stream = stream; - } - - /** - * Returns whether all elements of this stream match the provided predicate. May - * not evaluate the predicate on all elements if not necessary for determining - * the result. If the stream is empty then {@code true} is returned and the - * predicate is not evaluated. - * - *

- * This is a short-circuiting terminal operation. - * - * Note This method evaluates the universal quantification of the - * predicate over the elements of the stream (for all x P(x)). If the stream is - * empty, the quantification is said to be vacuously satisfied and is - * always {@code true} (regardless of P(x)). - * - * @param predicate A non-interfering, stateless predicate to apply to elements - * of this stream - * @return {@code true} If either all elements of the stream match the provided - * predicate or the stream is empty, otherwise {@code false}. - */ - public boolean allMatch(final FailablePredicate predicate) { - assertNotTerminated(); - return stream().allMatch(Failable.asPredicate(predicate)); - } - - /** - * Returns whether any elements of this stream match the provided predicate. May - * not evaluate the predicate on all elements if not necessary for determining - * the result. If the stream is empty then {@code false} is returned and the - * predicate is not evaluated. - * - *

- * This is a short-circuiting terminal operation. - * - * Note This method evaluates the existential quantification of the - * predicate over the elements of the stream (for some x P(x)). - * - * @param predicate A non-interfering, stateless predicate to apply to elements - * of this stream - * @return {@code true} if any elements of the stream match the provided - * predicate, otherwise {@code false} - */ - public boolean anyMatch(final FailablePredicate predicate) { - assertNotTerminated(); - return stream().anyMatch(Failable.asPredicate(predicate)); - } - - protected void assertNotTerminated() { - if (terminated) { - throw new IllegalStateException("This stream is already terminated."); - } - } - - /** - * Performs a mutable reduction operation on the elements of this stream using a - * {@code Collector}. A {@code Collector} encapsulates the functions used as - * arguments to {@link #collect(Supplier, BiConsumer, BiConsumer)}, allowing for - * reuse of collection strategies and composition of collect operations such as - * multiple-level grouping or partitioning. - * - *

- * If the underlying stream is parallel, and the {@code Collector} is - * concurrent, and either the stream is unordered or the collector is unordered, - * then a concurrent reduction will be performed (see {@link Collector} for - * details on concurrent reduction.) - * - *

- * This is a terminal operation. - * - *

- * When executed in parallel, multiple intermediate results may be instantiated, - * populated, and merged so as to maintain isolation of mutable data structures. - * Therefore, even when executed in parallel with non-thread-safe data - * structures (such as {@code ArrayList}), no additional synchronization is - * needed for a parallel reduction. - * - * Note The following will accumulate strings into an ArrayList: - * - *

-		 * {
-		 * 	@code
-		 * 	List asList = stringStream.collect(Collectors.toList());
-		 * }
-		 * 
- * - *

- * The following will classify {@code Person} objects by city: - * - *

-		 * {
-		 * 	@code
-		 * 	Map> peopleByCity = personStream.collect(Collectors.groupingBy(Person::getCity));
-		 * }
-		 * 
- * - *

- * The following will classify {@code Person} objects by state and city, - * cascading two {@code Collector}s together: - * - *

-		 * {
-		 * 	@code
-		 * 	Map>> peopleByStateAndCity = personStream
-		 * 			.collect(Collectors.groupingBy(Person::getState, Collectors.groupingBy(Person::getCity)));
-		 * }
-		 * 
- * - * @param the type of the result - * @param the intermediate accumulation type of the {@code Collector} - * @param collector the {@code Collector} describing the reduction - * @return the result of the reduction - * @see #collect(Supplier, BiConsumer, BiConsumer) - * @see Collectors - */ - public R collect(final Collector collector) { - makeTerminated(); - return stream().collect(collector); - } - - /** - * Performs a mutable reduction operation on the elements of this - * FailableStream. A mutable reduction is one in which the reduced value is a - * mutable result container, such as an {@code ArrayList}, and elements are - * incorporated by updating the state of the result rather than by replacing the - * result. This produces a result equivalent to: - * - *
-		 * {@code
-		 *     R result = supplier.get();
-		 *     for (T element : this stream)
-		 *         accumulator.accept(result, element);
-		 *     return result;
-		 * }
-		 * 
- * - *

- * Like {@link #reduce(Object, BinaryOperator)}, {@code collect} operations can - * be parallelized without requiring additional synchronization. - * - *

- * This is a terminal operation. - * - * Note There are many existing classes in the JDK whose signatures are - * well-suited for use with method references as arguments to {@code collect()}. - * For example, the following will accumulate strings into an {@code ArrayList}: - * - *

-		 * {
-		 * 	@code
-		 * 	List asList = stringStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
-		 * }
-		 * 
- * - *

- * The following will take a stream of strings and concatenates them into a - * single string: - * - *

-		 * {
-		 * 	@code
-		 * 	String concat = stringStream.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
-		 * 			.toString();
-		 * }
-		 * 
- * - * @param type of the result - * @param
Type of the accumulator. - * @param pupplier a function that creates a new result container. For a - * parallel execution, this function may be called multiple - * times and must return a fresh value each time. - * @param accumulator An associative, non-interfering, stateless function for - * incorporating an additional element into a result - * @param combiner An associative, non-interfering, stateless function for - * combining two values, which must be compatible with the - * accumulator function - * @return The result of the reduction - */ - public R collect(final Supplier pupplier, final BiConsumer accumulator, - final BiConsumer combiner) { - makeTerminated(); - return stream().collect(pupplier, accumulator, combiner); - } - - /** - * Returns a FailableStream consisting of the elements of this stream that match - * the given FailablePredicate. - * - *

- * This is an intermediate operation. - * - * @param predicate a non-interfering, stateless predicate to apply to each - * element to determine if it should be included. - * @return the new stream - */ - public FailableStream filter(final FailablePredicate predicate) { - assertNotTerminated(); - stream = stream.filter(Failable.asPredicate(predicate)); - return this; - } - - /** - * Performs an action for each element of this stream. - * - *

- * This is a terminal operation. - * - *

- * The behavior of this operation is explicitly nondeterministic. For parallel - * stream pipelines, this operation does not guarantee to respect the - * encounter order of the stream, as doing so would sacrifice the benefit of - * parallelism. For any given element, the action may be performed at whatever - * time and in whatever thread the library chooses. If the action accesses - * shared state, it is responsible for providing the required synchronization. - * - * @param action a non-interfering action to perform on the elements - */ - public void forEach(final FailableConsumer action) { - makeTerminated(); - stream().forEach(Failable.asConsumer(action)); - } - - protected void makeTerminated() { - assertNotTerminated(); - terminated = true; - } - - /** - * Returns a stream consisting of the results of applying the given function to - * the elements of this stream. - * - *

- * This is an intermediate operation. - * - * @param The element type of the new stream - * @param mapper A non-interfering, stateless function to apply to each element - * @return the new stream - */ - public FailableStream map(final FailableFunction mapper) { - assertNotTerminated(); - return new FailableStream<>(stream.map(Failable.asFunction(mapper))); - } - - /** - * Performs a reduction on the elements of this stream, using the provided - * identity value and an associative accumulation function, and returns the - * reduced value. This is equivalent to: - * - *

-		 * {@code
-		 *     T result = identity;
-		 *     for (T element : this stream)
-		 *         result = accumulator.apply(result, element)
-		 *     return result;
-		 * }
-		 * 
- * - * but is not constrained to execute sequentially. - * - *

- * The {@code identity} value must be an identity for the accumulator function. - * This means that for all {@code t}, {@code accumulator.apply(identity, t)} is - * equal to {@code t}. The {@code accumulator} function must be an associative - * function. - * - *

- * This is a terminal operation. - * - * Note Sum, min, max, average, and string concatenation are all special cases - * of reduction. Summing a stream of numbers can be expressed as: - * - *

-		 * {
-		 * 	@code
-		 * 	Integer sum = integers.reduce(0, (a, b) -> a + b);
-		 * }
-		 * 
- * - * or: - * - *
-		 * {
-		 * 	@code
-		 * 	Integer sum = integers.reduce(0, Integer::sum);
-		 * }
-		 * 
- * - *

- * While this may seem a more roundabout way to perform an aggregation compared - * to simply mutating a running total in a loop, reduction operations - * parallelize more gracefully, without needing additional synchronization and - * with greatly reduced risk of data races. - * - * @param identity the identity value for the accumulating function - * @param accumulator an associative, non-interfering, stateless function for - * combining two values - * @return the result of the reduction - */ - public O reduce(final O identity, final BinaryOperator accumulator) { - makeTerminated(); - return stream().reduce(identity, accumulator); - } - - /** - * Converts the FailableStream into an equivalent stream. - * - * @return A stream, which will return the same elements, which this - * FailableStream would return. - */ - public Stream stream() { - return stream; - } - } - - /** - * Converts the given {@link Collection} into a {@link FailableStream}. This is - * basically a simplified, reduced version of the {@link Stream} class, with the - * same underlying element stream, except that failable objects, like - * {@link FailablePredicate}, {@link FailableFunction}, or - * {@link FailableConsumer} may be applied, instead of {@link Predicate}, - * {@link Function}, or {@link Consumer}. The idea is to rewrite a code snippet - * like this: - * - *

-	 * final List<O> list;
-	 * final Method m;
-	 * final Function<O, String> mapper = (o) -> {
-	 * 	try {
-	 * 		return (String) m.invoke(o);
-	 * 	} catch (Throwable t) {
-	 * 		throw Failable.rethrow(t);
-	 * 	}
-	 * };
-	 * final List<String> strList = list.stream().map(mapper).collect(Collectors.toList());
-	 * 
- * - * as follows: - * - *
-	 * final List<O> list;
-	 * final Method m;
-	 * final List<String> strList = Failable.stream(list.stream()).map((o) -> (String) m.invoke(o))
-	 * 		.collect(Collectors.toList());
-	 * 
- * - * While the second version may not be quite as efficient (because it - * depends on the creation of additional, intermediate objects, of type - * FailableStream), it is much more concise, and readable, and meets the spirit - * of Lambdas better than the first version. - * - * @param The streams element type. - * @param stream The stream, which is being converted. - * @return The {@link FailableStream}, which has been created by converting the - * stream. - */ - public static FailableStream stream(final Collection stream) { - return stream(stream.stream()); - } - - /** - * Converts the given {@link Stream stream} into a {@link FailableStream}. This - * is basically a simplified, reduced version of the {@link Stream} class, with - * the same underlying element stream, except that failable objects, like - * {@link FailablePredicate}, {@link FailableFunction}, or - * {@link FailableConsumer} may be applied, instead of {@link Predicate}, - * {@link Function}, or {@link Consumer}. The idea is to rewrite a code snippet - * like this: - * - *
-	 * final List<O> list;
-	 * final Method m;
-	 * final Function<O, String> mapper = (o) -> {
-	 * 	try {
-	 * 		return (String) m.invoke(o);
-	 * 	} catch (Throwable t) {
-	 * 		throw Failable.rethrow(t);
-	 * 	}
-	 * };
-	 * final List<String> strList = list.stream().map(mapper).collect(Collectors.toList());
-	 * 
- * - * as follows: - * - *
-	 * final List<O> list;
-	 * final Method m;
-	 * final List<String> strList = Failable.stream(list.stream()).map((o) -> (String) m.invoke(o))
-	 * 		.collect(Collectors.toList());
-	 * 
- * - * While the second version may not be quite as efficient (because it - * depends on the creation of additional, intermediate objects, of type - * FailableStream), it is much more concise, and readable, and meets the spirit - * of Lambdas better than the first version. - * - * @param The streams element type. - * @param stream The stream, which is being converted. - * @return The {@link FailableStream}, which has been created by converting the - * stream. - */ - public static FailableStream stream(final Stream stream) { - return new FailableStream<>(stream); - } - - /** - * Returns a {@code Collector} that accumulates the input elements into a new - * array. - * - * @param pElementType Type of an element in the array. - * @param the type of the input elements - * @return a {@code Collector} which collects all the input elements into an - * array, in encounter order - */ - public static Collector toArray(final Class pElementType) { - return new ArrayCollector<>(pElementType); - } -} diff --git a/sources/main/java/org/apache/commons/lang3/stream/package-info.java b/sources/main/java/org/apache/commons/lang3/stream/package-info.java deleted file mode 100644 index 5dfe410d..00000000 --- a/sources/main/java/org/apache/commons/lang3/stream/package-info.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Provides utility classes to complement those in {@code java.util.stream}. - * - *

- * Contains utilities to allow streaming of failable functional interfaces from - * the {@code org.apache.commons.lang3.functions} package allowing streaming of - * functional expressions that may raise an Exception. - * - * @since 3.11 - */ -package org.apache.commons.lang3.stream; diff --git a/sources/main/java/org/apache/commons/lang3/text/CompositeFormat.java b/sources/main/java/org/apache/commons/lang3/text/CompositeFormat.java deleted file mode 100644 index 112967bb..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/CompositeFormat.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text; - -import java.text.FieldPosition; -import java.text.Format; -import java.text.ParseException; -import java.text.ParsePosition; - -/** - * Formats using one formatter and parses using a different formatter. An - * example of use for this would be a webapp where data is taken in one way and - * stored in a database another way. - * - * @!deprecated as of 3.6, use commons-text - * CompositeFormat instead - */ -//@Deprecated -public class CompositeFormat extends Format { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = -4329119827877627683L; - - /** The parser to use. */ - private final Format parser; - /** The formatter to use. */ - private final Format formatter; - - /** - * Create a format that points its parseObject method to one implementation and - * its format method to another. - * - * @param parser implementation - * @param formatter implementation - */ - public CompositeFormat(final Format parser, final Format formatter) { - this.parser = parser; - this.formatter = formatter; - } - - /** - * Uses the formatter Format instance. - * - * @param obj the object to format - * @param toAppendTo the {@link StringBuffer} to append to - * @param pos the FieldPosition to use (or ignore). - * @return {@code toAppendTo} - * @see Format#format(Object, StringBuffer, FieldPosition) - */ - @Override // Therefore has to use StringBuffer - public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) { - return formatter.format(obj, toAppendTo, pos); - } - - /** - * Uses the parser Format instance. - * - * @param source the String source - * @param pos the ParsePosition containing the position to parse from, will - * be updated according to parsing success (index) or failure - * (error index) - * @return the parsed Object - * @see Format#parseObject(String, ParsePosition) - */ - @Override - public Object parseObject(final String source, final ParsePosition pos) { - return parser.parseObject(source, pos); - } - - /** - * Provides access to the parser Format implementation. - * - * @return parser Format implementation - */ - public Format getParser() { - return this.parser; - } - - /** - * Provides access to the parser Format implementation. - * - * @return formatter Format implementation - */ - public Format getFormatter() { - return this.formatter; - } - - /** - * Utility method to parse and then reformat a String. - * - * @param input String to reformat - * @return A reformatted String - * @throws ParseException thrown by parseObject(String) call - */ - public String reformat(final String input) throws ParseException { - return format(parseObject(input)); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/ExtendedMessageFormat.java b/sources/main/java/org/apache/commons/lang3/text/ExtendedMessageFormat.java deleted file mode 100644 index ee90728d..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/ExtendedMessageFormat.java +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text; - -import java.text.Format; -import java.text.MessageFormat; -import java.text.ParsePosition; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; - -import org.apache.commons.lang3.LocaleUtils; -import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.Validate; - -/** - * Extends {@code java.text.MessageFormat} to allow pluggable/additional - * formatting options for embedded format elements. Client code should specify a - * registry of {@code FormatFactory} instances associated with {@code String} - * format names. This registry will be consulted when the format elements are - * parsed from the message pattern. In this way custom patterns can be - * specified, and the formats supported by {@code java.text.MessageFormat} can - * be overridden at the format and/or format style level (see MessageFormat). A - * "format element" embedded in the message pattern is specified (()? - * signifies optionality):
- * {argument-number({@code ,}format-name - * ({@code ,}format-style)?)?} - * - *

- * format-name and format-style values are trimmed of surrounding - * whitespace in the manner of {@code java.text.MessageFormat}. If - * format-name denotes {@code FormatFactory formatFactoryInstance} in - * {@code registry}, a {@code Format} matching format-name and - * format-style is requested from {@code formatFactoryInstance}. If this - * is successful, the {@code Format} found is used for this format element. - *

- * - *

- * NOTICE: The various subformat mutator methods are considered - * unnecessary; they exist on the parent class to allow the type of - * customization which it is the job of this class to provide in a configurable - * fashion. These methods have thus been disabled and will throw - * {@code UnsupportedOperationException} if called. - *

- * - *

- * Limitations inherited from {@code java.text.MessageFormat}: - *

- *
    - *
  • When using "choice" subformats, support for nested formatting - * instructions is limited to that provided by the base class.
  • - *
  • Thread-safety of {@code Format}s, including {@code MessageFormat} and - * thus {@code ExtendedMessageFormat}, is not guaranteed.
  • - *
- * - * @since 2.4 - * @!deprecated as of 3.6, use commons-text - * ExtendedMessageFormat instead - */ -//@Deprecated -public class ExtendedMessageFormat extends MessageFormat { - private static final long serialVersionUID = -2362048321261811743L; - private static final int HASH_SEED = 31; - - private static final String DUMMY_PATTERN = ""; - private static final char START_FMT = ','; - private static final char END_FE = '}'; - private static final char START_FE = '{'; - private static final char QUOTE = '\''; - - private String toPattern; - private final Map registry; - - /** - * Create a new ExtendedMessageFormat for the default locale. - * - * @param pattern the pattern to use, not null - * @throws IllegalArgumentException in case of a bad pattern. - */ - public ExtendedMessageFormat(final String pattern) { - this(pattern, Locale.getDefault()); - } - - /** - * Create a new ExtendedMessageFormat. - * - * @param pattern the pattern to use, not null - * @param locale the locale to use, not null - * @throws IllegalArgumentException in case of a bad pattern. - */ - public ExtendedMessageFormat(final String pattern, final Locale locale) { - this(pattern, locale, null); - } - - /** - * Create a new ExtendedMessageFormat for the default locale. - * - * @param pattern the pattern to use, not null - * @param registry the registry of format factories, may be null - * @throws IllegalArgumentException in case of a bad pattern. - */ - public ExtendedMessageFormat(final String pattern, final Map registry) { - this(pattern, Locale.getDefault(), registry); - } - - /** - * Create a new ExtendedMessageFormat. - * - * @param pattern the pattern to use, not null. - * @param locale the locale to use. - * @param registry the registry of format factories, may be null. - * @throws IllegalArgumentException in case of a bad pattern. - */ - public ExtendedMessageFormat(final String pattern, final Locale locale, - final Map registry) { - super(DUMMY_PATTERN); - setLocale(LocaleUtils.toLocale(locale)); - this.registry = registry; - applyPattern(pattern); - } - - /** - * {@inheritDoc} - */ - @Override - public String toPattern() { - return toPattern; - } - - /** - * Apply the specified pattern. - * - * @param pattern String - */ - @Override - public final void applyPattern(final String pattern) { - if (registry == null) { - super.applyPattern(pattern); - toPattern = super.toPattern(); - return; - } - final ArrayList foundFormats = new ArrayList<>(); - final ArrayList foundDescriptions = new ArrayList<>(); - final StringBuilder stripCustom = new StringBuilder(pattern.length()); - - final ParsePosition pos = new ParsePosition(0); - final char[] c = pattern.toCharArray(); - int fmtCount = 0; - while (pos.getIndex() < pattern.length()) { - switch (c[pos.getIndex()]) { - case QUOTE: - appendQuotedString(pattern, pos, stripCustom); - break; - case START_FE: - fmtCount++; - seekNonWs(pattern, pos); - final int start = pos.getIndex(); - final int index = readArgumentIndex(pattern, next(pos)); - stripCustom.append(START_FE).append(index); - seekNonWs(pattern, pos); - Format format = null; - String formatDescription = null; - if (c[pos.getIndex()] == START_FMT) { - formatDescription = parseFormatDescription(pattern, next(pos)); - format = getFormat(formatDescription); - if (format == null) { - stripCustom.append(START_FMT).append(formatDescription); - } - } - foundFormats.add(format); - foundDescriptions.add(format == null ? null : formatDescription); - Validate.isTrue(foundFormats.size() == fmtCount); - Validate.isTrue(foundDescriptions.size() == fmtCount); - if (c[pos.getIndex()] != END_FE) { - throw new IllegalArgumentException("Unreadable format element at position " + start); - } - //$FALL-THROUGH$ - default: - stripCustom.append(c[pos.getIndex()]); - next(pos); - } - } - super.applyPattern(stripCustom.toString()); - toPattern = insertFormats(super.toPattern(), foundDescriptions); - if (containsElements(foundFormats)) { - final Format[] origFormats = getFormats(); - // only loop over what we know we have, as MessageFormat on Java 1.3 - // seems to provide an extra format element: - int i = 0; - for (final Iterator it = foundFormats.iterator(); it.hasNext(); i++) { - final Format f = it.next(); - if (f != null) { - origFormats[i] = f; - } - } - super.setFormats(origFormats); - } - } - - /** - * Throws UnsupportedOperationException - see class Javadoc for details. - * - * @param formatElementIndex format element index - * @param newFormat the new format - * @throws UnsupportedOperationException always thrown since this isn't - * supported by ExtendMessageFormat - */ - @Override - public void setFormat(final int formatElementIndex, final Format newFormat) { - throw new UnsupportedOperationException(); - } - - /** - * Throws UnsupportedOperationException - see class Javadoc for details. - * - * @param argumentIndex argument index - * @param newFormat the new format - * @throws UnsupportedOperationException always thrown since this isn't - * supported by ExtendMessageFormat - */ - @Override - public void setFormatByArgumentIndex(final int argumentIndex, final Format newFormat) { - throw new UnsupportedOperationException(); - } - - /** - * Throws UnsupportedOperationException - see class Javadoc for details. - * - * @param newFormats new formats - * @throws UnsupportedOperationException always thrown since this isn't - * supported by ExtendMessageFormat - */ - @Override - public void setFormats(final Format[] newFormats) { - throw new UnsupportedOperationException(); - } - - /** - * Throws UnsupportedOperationException - see class Javadoc for details. - * - * @param newFormats new formats - * @throws UnsupportedOperationException always thrown since this isn't - * supported by ExtendMessageFormat - */ - @Override - public void setFormatsByArgumentIndex(final Format[] newFormats) { - throw new UnsupportedOperationException(); - } - - /** - * Check if this extended message format is equal to another object. - * - * @param obj the object to compare to - * @return true if this object equals the other, otherwise false - */ - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (obj == null) { - return false; - } - if (!super.equals(obj)) { - return false; - } - if (ObjectUtils.notEqual(getClass(), obj.getClass())) { - return false; - } - final ExtendedMessageFormat rhs = (ExtendedMessageFormat) obj; - if (ObjectUtils.notEqual(toPattern, rhs.toPattern)) { - return false; - } - return !ObjectUtils.notEqual(registry, rhs.registry); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - int result = super.hashCode(); - result = HASH_SEED * result + Objects.hashCode(registry); - result = HASH_SEED * result + Objects.hashCode(toPattern); - return result; - } - - /** - * Gets a custom format from a format description. - * - * @param desc String - * @return Format - */ - private Format getFormat(final String desc) { - if (registry != null) { - String name = desc; - String args = null; - final int i = desc.indexOf(START_FMT); - if (i > 0) { - name = desc.substring(0, i).trim(); - args = desc.substring(i + 1).trim(); - } - final FormatFactory factory = registry.get(name); - if (factory != null) { - return factory.getFormat(name, args, getLocale()); - } - } - return null; - } - - /** - * Read the argument index from the current format element - * - * @param pattern pattern to parse - * @param pos current parse position - * @return argument index - */ - private int readArgumentIndex(final String pattern, final ParsePosition pos) { - final int start = pos.getIndex(); - seekNonWs(pattern, pos); - final StringBuilder result = new StringBuilder(); - boolean error = false; - for (; !error && pos.getIndex() < pattern.length(); next(pos)) { - char c = pattern.charAt(pos.getIndex()); - if (Character.isWhitespace(c)) { - seekNonWs(pattern, pos); - c = pattern.charAt(pos.getIndex()); - if (c != START_FMT && c != END_FE) { - error = true; - continue; - } - } - if ((c == START_FMT || c == END_FE) && result.length() > 0) { - try { - return Integer.parseInt(result.toString()); - } catch (final NumberFormatException e) { // NOPMD - // we've already ensured only digits, so unless something - // outlandishly large was specified we should be okay. - } - } - error = !Character.isDigit(c); - result.append(c); - } - if (error) { - throw new IllegalArgumentException("Invalid format argument index at position " + start + ": " - + pattern.substring(start, pos.getIndex())); - } - throw new IllegalArgumentException("Unterminated format element at position " + start); - } - - /** - * Parse the format component of a format element. - * - * @param pattern string to parse - * @param pos current parse position - * @return Format description String - */ - private String parseFormatDescription(final String pattern, final ParsePosition pos) { - final int start = pos.getIndex(); - seekNonWs(pattern, pos); - final int text = pos.getIndex(); - int depth = 1; - for (; pos.getIndex() < pattern.length(); next(pos)) { - switch (pattern.charAt(pos.getIndex())) { - case START_FE: - depth++; - break; - case END_FE: - depth--; - if (depth == 0) { - return pattern.substring(text, pos.getIndex()); - } - break; - case QUOTE: - getQuotedString(pattern, pos); - break; - default: - break; - } - } - throw new IllegalArgumentException("Unterminated format element at position " + start); - } - - /** - * Insert formats back into the pattern for toPattern() support. - * - * @param pattern source - * @param customPatterns The custom patterns to re-insert, if any - * @return full pattern - */ - private String insertFormats(final String pattern, final ArrayList customPatterns) { - if (!containsElements(customPatterns)) { - return pattern; - } - final StringBuilder sb = new StringBuilder(pattern.length() * 2); - final ParsePosition pos = new ParsePosition(0); - int fe = -1; - int depth = 0; - while (pos.getIndex() < pattern.length()) { - final char c = pattern.charAt(pos.getIndex()); - switch (c) { - case QUOTE: - appendQuotedString(pattern, pos, sb); - break; - case START_FE: - depth++; - sb.append(START_FE).append(readArgumentIndex(pattern, next(pos))); - // do not look for custom patterns when they are embedded, e.g. in a choice - if (depth == 1) { - fe++; - final String customPattern = customPatterns.get(fe); - if (customPattern != null) { - sb.append(START_FMT).append(customPattern); - } - } - break; - case END_FE: - depth--; - //$FALL-THROUGH$ - default: - sb.append(c); - next(pos); - } - } - return sb.toString(); - } - - /** - * Consume whitespace from the current parse position. - * - * @param pattern String to read - * @param pos current position - */ - private void seekNonWs(final String pattern, final ParsePosition pos) { - int len = 0; - final char[] buffer = pattern.toCharArray(); - do { - len = StrMatcher.splitMatcher().isMatch(buffer, pos.getIndex()); - pos.setIndex(pos.getIndex() + len); - } while (len > 0 && pos.getIndex() < pattern.length()); - } - - /** - * Convenience method to advance parse position by 1 - * - * @param pos ParsePosition - * @return {@code pos} - */ - private ParsePosition next(final ParsePosition pos) { - pos.setIndex(pos.getIndex() + 1); - return pos; - } - - /** - * Consume a quoted string, adding it to {@code appendTo} if specified. - * - * @param pattern pattern to parse - * @param pos current parse position - * @param appendTo optional StringBuilder to append - * @return {@code appendTo} - */ - private StringBuilder appendQuotedString(final String pattern, final ParsePosition pos, - final StringBuilder appendTo) { - assert pattern.toCharArray()[pos.getIndex()] == QUOTE : "Quoted string must start with quote character"; - - // handle quote character at the beginning of the string - if (appendTo != null) { - appendTo.append(QUOTE); - } - next(pos); - - final int start = pos.getIndex(); - final char[] c = pattern.toCharArray(); - final int lastHold = start; - for (int i = pos.getIndex(); i < pattern.length(); i++) { - if (c[pos.getIndex()] == QUOTE) { - next(pos); - return appendTo == null ? null : appendTo.append(c, lastHold, pos.getIndex() - lastHold); - } - next(pos); - } - throw new IllegalArgumentException("Unterminated quoted string at position " + start); - } - - /** - * Consume quoted string only - * - * @param pattern pattern to parse - * @param pos current parse position - */ - private void getQuotedString(final String pattern, final ParsePosition pos) { - appendQuotedString(pattern, pos, null); - } - - /** - * Learn whether the specified Collection contains non-null elements. - * - * @param coll to check - * @return {@code true} if some Object was found, {@code false} otherwise. - */ - private boolean containsElements(final Collection coll) { - if (coll == null || coll.isEmpty()) { - return false; - } - for (final Object name : coll) { - if (name != null) { - return true; - } - } - return false; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/text/FormatFactory.java b/sources/main/java/org/apache/commons/lang3/text/FormatFactory.java deleted file mode 100644 index 86e7933f..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/FormatFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text; - -import java.text.Format; -import java.util.Locale; - -/** - * Format factory. - * - * @since 2.4 - * @!deprecated as of 3.6, use commons-text - * FormatFactory instead - */ -//@Deprecated -public interface FormatFactory { - - /** - * Create or retrieve a format instance. - * - * @param name The format type name - * @param arguments Arguments used to create the format instance. This allows - * the {@code FormatFactory} to implement the "format style" - * concept from {@code java.text.MessageFormat}. - * @param locale The locale, may be null - * @return The format instance - */ - Format getFormat(String name, String arguments, Locale locale); - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/FormattableUtils.java b/sources/main/java/org/apache/commons/lang3/text/FormattableUtils.java deleted file mode 100644 index fd8fe4d7..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/FormattableUtils.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text; - -import static java.util.FormattableFlags.LEFT_JUSTIFY; - -import java.util.Formattable; -import java.util.Formatter; - -import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; - -import net.lax1dude.eaglercraft.v1_8.HString; - -/** - *

- * Provides utilities for working with the {@code Formattable} interface. - *

- * - *

- * The {@link Formattable} interface provides basic control over formatting when - * using a {@code Formatter}. It is primarily concerned with numeric precision - * and padding, and is not designed to allow generalised alternate formats. - *

- * - * @since 3.0 - * @!deprecated as of 3.6, use commons-text - * FormattableUtils instead - */ -//@Deprecated -public class FormattableUtils { - - /** - * A format that simply outputs the value as a string. - */ - private static final String SIMPLEST_FORMAT = "%s"; - - /** - *

- * {@code FormattableUtils} instances should NOT be constructed in standard - * programming. Instead, the methods of the class should be invoked statically. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public FormattableUtils() { - } - - // ----------------------------------------------------------------------- - /** - * Gets the default formatted representation of the specified - * {@code Formattable}. - * - * @param formattable the instance to convert to a string, not null - * @return the resulting string, not null - */ - public static String toString(final Formattable formattable) { - return HString.format(SIMPLEST_FORMAT, formattable); - } - - /** - * Handles the common {@code Formattable} operations of truncate-pad-append, - * with no ellipsis on precision overflow, and padding width underflow with - * spaces. - * - * @param seq the string to handle, not null - * @param formatter the destination formatter, not null - * @param flags the flags for formatting, see {@code Formattable} - * @param width the width of the output, see {@code Formattable} - * @param precision the precision of the output, see {@code Formattable} - * @return the {@code formatter} instance, not null - */ - public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, - final int precision) { - return append(seq, formatter, flags, width, precision, ' ', null); - } - - /** - * Handles the common {@link Formattable} operations of truncate-pad-append, - * with no ellipsis on precision overflow. - * - * @param seq the string to handle, not null - * @param formatter the destination formatter, not null - * @param flags the flags for formatting, see {@code Formattable} - * @param width the width of the output, see {@code Formattable} - * @param precision the precision of the output, see {@code Formattable} - * @param padChar the pad character to use - * @return the {@code formatter} instance, not null - */ - public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, - final int precision, final char padChar) { - return append(seq, formatter, flags, width, precision, padChar, null); - } - - /** - * Handles the common {@link Formattable} operations of truncate-pad-append, - * padding width underflow with spaces. - * - * @param seq the string to handle, not null - * @param formatter the destination formatter, not null - * @param flags the flags for formatting, see {@code Formattable} - * @param width the width of the output, see {@code Formattable} - * @param precision the precision of the output, see {@code Formattable} - * @param ellipsis the ellipsis to use when precision dictates truncation, null - * or empty causes a hard truncation - * @return the {@code formatter} instance, not null - */ - public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, - final int precision, final CharSequence ellipsis) { - return append(seq, formatter, flags, width, precision, ' ', ellipsis); - } - - /** - * Handles the common {@link Formattable} operations of truncate-pad-append. - * - * @param seq the string to handle, not null - * @param formatter the destination formatter, not null - * @param flags the flags for formatting, see {@code Formattable} - * @param width the width of the output, see {@code Formattable} - * @param precision the precision of the output, see {@code Formattable} - * @param padChar the pad character to use - * @param ellipsis the ellipsis to use when precision dictates truncation, null - * or empty causes a hard truncation - * @return the {@code formatter} instance, not null - */ - public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, - final int precision, final char padChar, final CharSequence ellipsis) { - Validate.isTrue(ellipsis == null || precision < 0 || ellipsis.length() <= precision, - "Specified ellipsis '%1$s' exceeds precision of %2$s", ellipsis, Integer.valueOf(precision)); - final StringBuilder buf = new StringBuilder(seq); - if (precision >= 0 && precision < seq.length()) { - final CharSequence _ellipsis = ObjectUtils.defaultIfNull(ellipsis, StringUtils.EMPTY); - buf.replace(precision - _ellipsis.length(), seq.length(), _ellipsis.toString()); - } - final boolean leftJustify = (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY; - for (int i = buf.length(); i < width; i++) { - buf.insert(leftJustify ? i : 0, padChar); - } - formatter.format(buf.toString()); - return formatter; - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/StrBuilder.java b/sources/main/java/org/apache/commons/lang3/text/StrBuilder.java deleted file mode 100644 index 6fd0a5bb..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/StrBuilder.java +++ /dev/null @@ -1,3143 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text; - -import java.io.IOException; -import java.io.Reader; -import java.io.Serializable; -import java.io.Writer; -import java.nio.CharBuffer; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; - -import net.lax1dude.eaglercraft.v1_8.HString; - -import org.apache.commons.lang3.CharUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.builder.Builder; - -/** - * Builds a string from constituent parts providing a more flexible and powerful - * API than StringBuffer. - *

- * The main differences from StringBuffer/StringBuilder are: - *

- *
    - *
  • Not synchronized
  • - *
  • Not final
  • - *
  • Subclasses have direct access to character array
  • - *
  • Additional methods - *
      - *
    • appendWithSeparators - adds an array of values, with a separator
    • - *
    • appendPadding - adds a length padding characters
    • - *
    • appendFixedLength - adds a fixed width field to the builder
    • - *
    • toCharArray/getChars - simpler ways to get a range of the character - * array
    • - *
    • delete - delete char or string
    • - *
    • replace - search and replace for a char or string
    • - *
    • leftString/rightString/midString - substring without exceptions
    • - *
    • contains - whether the builder contains a char or string
    • - *
    • size/clear/isEmpty - collections style API methods
    • - *
    - *
  • - *
  • Views - *
      - *
    • asTokenizer - uses the internal buffer as the source of a - * StrTokenizer
    • - *
    • asReader - uses the internal buffer as the source of a Reader
    • - *
    • asWriter - allows a Writer to write directly to the internal buffer
    • - *
    - *
  • - *
- *

- * The aim has been to provide an API that mimics very closely what StringBuffer - * provides, but with additional methods. It should be noted that some edge - * cases, with invalid indices or null input, have been altered - see individual - * methods. The biggest of these changes is that by default, null will not - * output the text 'null'. This can be controlled by a property, - * {@link #setNullText(String)}. - *

- * Prior to 3.0, this class implemented Cloneable but did not implement the - * clone method so could not be used. From 3.0 onwards it no longer implements - * the interface. - * - * @since 2.2 - * @!deprecated as of 3.6, use commons-text - * TextStringBuilder instead - */ -//@Deprecated -public class StrBuilder implements CharSequence, Appendable, Serializable, Builder { - - /** - * The extra capacity for new builders. - */ - static final int CAPACITY = 32; - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 7628716375283629643L; - - /** Internal data storage. */ - protected char[] buffer; // TODO make private? - /** Current size of the buffer. */ - protected int size; // TODO make private? - /** The new line. */ - private String newLine; - /** The null text. */ - private String nullText; - - // ----------------------------------------------------------------------- - /** - * Constructor that creates an empty builder initial capacity 32 characters. - */ - public StrBuilder() { - this(CAPACITY); - } - - /** - * Constructor that creates an empty builder the specified initial capacity. - * - * @param initialCapacity the initial capacity, zero or less will be converted - * to 32 - */ - public StrBuilder(int initialCapacity) { - if (initialCapacity <= 0) { - initialCapacity = CAPACITY; - } - buffer = new char[initialCapacity]; - } - - /** - * Constructor that creates a builder from the string, allocating 32 extra - * characters for growth. - * - * @param str the string to copy, null treated as blank string - */ - public StrBuilder(final String str) { - if (str == null) { - buffer = new char[CAPACITY]; - } else { - buffer = new char[str.length() + CAPACITY]; - append(str); - } - } - - // ----------------------------------------------------------------------- - /** - * Gets the text to be appended when a new line is added. - * - * @return the new line text, null means use system default - */ - public String getNewLineText() { - return newLine; - } - - /** - * Sets the text to be appended when a new line is added. - * - * @param newLine the new line text, null means use system default - * @return this, to enable chaining - */ - public StrBuilder setNewLineText(final String newLine) { - this.newLine = newLine; - return this; - } - - // ----------------------------------------------------------------------- - /** - * Gets the text to be appended when null is added. - * - * @return the null text, null means no append - */ - public String getNullText() { - return nullText; - } - - /** - * Sets the text to be appended when null is added. - * - * @param nullText the null text, null means no append - * @return this, to enable chaining - */ - public StrBuilder setNullText(String nullText) { - if (nullText != null && nullText.isEmpty()) { - nullText = null; - } - this.nullText = nullText; - return this; - } - - // ----------------------------------------------------------------------- - /** - * Gets the length of the string builder. - * - * @return the length - */ - @Override - public int length() { - return size; - } - - /** - * Updates the length of the builder by either dropping the last characters or - * adding filler of Unicode zero. - * - * @param length the length to set to, must be zero or positive - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the length is negative - */ - public StrBuilder setLength(final int length) { - if (length < 0) { - throw new StringIndexOutOfBoundsException(length); - } - if (length < size) { - size = length; - } else if (length > size) { - ensureCapacity(length); - final int oldEnd = size; - final int newEnd = length; - size = length; - for (int i = oldEnd; i < newEnd; i++) { - buffer[i] = CharUtils.NUL; - } - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Gets the current size of the internal character array buffer. - * - * @return the capacity - */ - public int capacity() { - return buffer.length; - } - - /** - * Checks the capacity and ensures that it is at least the size specified. - * - * @param capacity the capacity to ensure - * @return this, to enable chaining - */ - public StrBuilder ensureCapacity(final int capacity) { - if (capacity > buffer.length) { - final char[] old = buffer; - buffer = new char[capacity * 2]; - System.arraycopy(old, 0, buffer, 0, size); - } - return this; - } - - /** - * Minimizes the capacity to the actual length of the string. - * - * @return this, to enable chaining - */ - public StrBuilder minimizeCapacity() { - if (buffer.length > length()) { - final char[] old = buffer; - buffer = new char[length()]; - System.arraycopy(old, 0, buffer, 0, size); - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Gets the length of the string builder. - *

- * This method is the same as {@link #length()} and is provided to match the API - * of Collections. - * - * @return the length - */ - public int size() { - return size; - } - - /** - * Checks is the string builder is empty (convenience Collections API style - * method). - *

- * This method is the same as checking {@link #length()} and is provided to - * match the API of Collections. - * - * @return {@code true} if the size is {@code 0}. - */ - public boolean isEmpty() { - return size == 0; - } - - /** - * Checks is the string builder is not empty (convenience Collections API style - * method). - *

- * This method is the same as checking {@link #length()} and is provided to - * match the API of Collections. - * - * @return {@code true} if the size is greater than {@code 0}. - * @since 3.12.0 - */ - public boolean isNotEmpty() { - return size > 0; - } - - /** - * Clears the string builder (convenience Collections API style method). - *

- * This method does not reduce the size of the internal character buffer. To do - * that, call {@code clear()} followed by {@link #minimizeCapacity()}. - *

- * This method is the same as {@link #setLength(int)} called with zero and is - * provided to match the API of Collections. - * - * @return this, to enable chaining - */ - public StrBuilder clear() { - size = 0; - return this; - } - - // ----------------------------------------------------------------------- - /** - * Gets the character at the specified index. - * - * @see #setCharAt(int, char) - * @see #deleteCharAt(int) - * @param index the index to retrieve, must be valid - * @return the character at the index - * @throws IndexOutOfBoundsException if the index is invalid - */ - @Override - public char charAt(final int index) { - if (index < 0 || index >= length()) { - throw new StringIndexOutOfBoundsException(index); - } - return buffer[index]; - } - - /** - * Sets the character at the specified index. - * - * @see #charAt(int) - * @see #deleteCharAt(int) - * @param index the index to set - * @param ch the new character - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder setCharAt(final int index, final char ch) { - if (index < 0 || index >= length()) { - throw new StringIndexOutOfBoundsException(index); - } - buffer[index] = ch; - return this; - } - - /** - * Deletes the character at the specified index. - * - * @see #charAt(int) - * @see #setCharAt(int, char) - * @param index the index to delete - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder deleteCharAt(final int index) { - if (index < 0 || index >= size) { - throw new StringIndexOutOfBoundsException(index); - } - deleteImpl(index, index + 1, 1); - return this; - } - - // ----------------------------------------------------------------------- - /** - * Copies the builder's character array into a new character array. - * - * @return a new array that represents the contents of the builder - */ - public char[] toCharArray() { - if (size == 0) { - return new char[0]; - } - final char[] chars = new char[size]; - System.arraycopy(buffer, 0, chars, 0, size); - return chars; - } - - /** - * Copies part of the builder's character array into a new character array. - * - * @param startIndex the start index, inclusive, must be valid - * @param endIndex the end index, exclusive, must be valid except that if too - * large it is treated as end of string - * @return a new array that holds part of the contents of the builder - * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is - * invalid (but endIndex greater than size is - * valid) - */ - public char[] toCharArray(final int startIndex, int endIndex) { - endIndex = validateRange(startIndex, endIndex); - final int len = endIndex - startIndex; - if (len == 0) { - return new char[0]; - } - final char[] chars = new char[len]; - System.arraycopy(buffer, startIndex, chars, 0, len); - return chars; - } - - /** - * Copies the character array into the specified array. - * - * @param destination the destination array, null will cause an array to be - * created - * @return the input array, unless that was null or too small - */ - public char[] getChars(char[] destination) { - final int len = length(); - if (destination == null || destination.length < len) { - destination = new char[len]; - } - System.arraycopy(buffer, 0, destination, 0, len); - return destination; - } - - /** - * Copies the character array into the specified array. - * - * @param startIndex first index to copy, inclusive, must be valid - * @param endIndex last index, exclusive, must be valid - * @param destination the destination array, must not be null or too small - * @param destinationIndex the index to start copying in destination - * @throws NullPointerException if the array is null - * @throws IndexOutOfBoundsException if any index is invalid - */ - public void getChars(final int startIndex, final int endIndex, final char[] destination, - final int destinationIndex) { - if (startIndex < 0) { - throw new StringIndexOutOfBoundsException(startIndex); - } - if (endIndex < 0 || endIndex > length()) { - throw new StringIndexOutOfBoundsException(endIndex); - } - if (startIndex > endIndex) { - throw new StringIndexOutOfBoundsException("end < start"); - } - System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex); - } - - // ----------------------------------------------------------------------- - /** - * If possible, reads chars from the provided {@link Readable} directly into - * underlying character buffer without making extra copies. - * - * @param readable object to read from - * @return the number of characters read - * @throws IOException if an I/O error occurs. - * - * @since 3.4 - * @see #appendTo(Appendable) - */ - public int readFrom(final Readable readable) throws IOException { - final int oldSize = size; - if (readable instanceof Reader) { - final Reader r = (Reader) readable; - ensureCapacity(size + 1); - int read; - while ((read = r.read(buffer, size, buffer.length - size)) != -1) { - size += read; - ensureCapacity(size + 1); - } - } else if (readable instanceof CharBuffer) { - final CharBuffer cb = (CharBuffer) readable; - final int remaining = cb.remaining(); - ensureCapacity(size + remaining); - cb.get(buffer, size, remaining); - size += remaining; - } else { - while (true) { - ensureCapacity(size + 1); - final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size); - final int read = readable.read(buf); - if (read == -1) { - break; - } - size += read; - } - } - return size - oldSize; - } - - // ----------------------------------------------------------------------- - /** - * Appends the new line string to this string builder. - *

- * The new line string can be altered using {@link #setNewLineText(String)}. - * This might be used to force the output to always use Unix line endings even - * when on Windows. - * - * @return this, to enable chaining - */ - public StrBuilder appendNewLine() { - if (newLine == null) { - append(System.lineSeparator()); - return this; - } - return append(newLine); - } - - /** - * Appends the text representing {@code null} to this string builder. - * - * @return this, to enable chaining - */ - public StrBuilder appendNull() { - if (nullText == null) { - return this; - } - return append(nullText); - } - - /** - * Appends an object to this string builder. Appending null will call - * {@link #appendNull()}. - * - * @param obj the object to append - * @return this, to enable chaining - */ - public StrBuilder append(final Object obj) { - if (obj == null) { - return appendNull(); - } - if (obj instanceof CharSequence) { - return append((CharSequence) obj); - } - return append(obj.toString()); - } - - /** - * Appends a CharSequence to this string builder. Appending null will call - * {@link #appendNull()}. - * - * @param seq the CharSequence to append - * @return this, to enable chaining - * @since 3.0 - */ - @Override - public StrBuilder append(final CharSequence seq) { - if (seq == null) { - return appendNull(); - } - if (seq instanceof StrBuilder) { - return append((StrBuilder) seq); - } - if (seq instanceof StringBuilder) { - return append((StringBuilder) seq); - } - if (seq instanceof StringBuffer) { - return append((StringBuffer) seq); - } - if (seq instanceof CharBuffer) { - return append((CharBuffer) seq); - } - return append(seq.toString()); - } - - /** - * Appends part of a CharSequence to this string builder. Appending null will - * call {@link #appendNull()}. - * - * @param seq the CharSequence to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - * @since 3.0 - */ - @Override - public StrBuilder append(final CharSequence seq, final int startIndex, final int length) { - if (seq == null) { - return appendNull(); - } - return append(seq.toString(), startIndex, length); - } - - /** - * Appends a string to this string builder. Appending null will call - * {@link #appendNull()}. - * - * @param str the string to append - * @return this, to enable chaining - */ - public StrBuilder append(final String str) { - if (str == null) { - return appendNull(); - } - final int strLen = str.length(); - if (strLen > 0) { - final int len = length(); - ensureCapacity(len + strLen); - str.getChars(0, strLen, buffer, len); - size += strLen; - } - return this; - } - - /** - * Appends part of a string to this string builder. Appending null will call - * {@link #appendNull()}. - * - * @param str the string to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - */ - public StrBuilder append(final String str, final int startIndex, final int length) { - if (str == null) { - return appendNull(); - } - if (startIndex < 0 || startIndex > str.length()) { - throw new StringIndexOutOfBoundsException("startIndex must be valid"); - } - if (length < 0 || (startIndex + length) > str.length()) { - throw new StringIndexOutOfBoundsException("length must be valid"); - } - if (length > 0) { - final int len = length(); - ensureCapacity(len + length); - str.getChars(startIndex, startIndex + length, buffer, len); - size += length; - } - return this; - } - - /** - * Calls {@link String#format(String, Object...)} and appends the result. - * - * @param format the format string - * @param objs the objects to use in the format string - * @return {@code this} to enable chaining - * @see String#format(String, Object...) - * @since 3.2 - */ - public StrBuilder append(final String format, final Object... objs) { - return append(HString.format(format, objs)); - } - - /** - * Appends the contents of a char buffer to this string builder. Appending null - * will call {@link #appendNull()}. - * - * @param buf the char buffer to append - * @return this, to enable chaining - * @since 3.4 - */ - public StrBuilder append(final CharBuffer buf) { - if (buf == null) { - return appendNull(); - } - if (buf.hasArray()) { - final int length = buf.remaining(); - final int len = length(); - ensureCapacity(len + length); - System.arraycopy(buf.array(), buf.arrayOffset() + buf.position(), buffer, len, length); - size += length; - } else { - append(buf.toString()); - } - return this; - } - - /** - * Appends the contents of a char buffer to this string builder. Appending null - * will call {@link #appendNull()}. - * - * @param buf the char buffer to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - * @since 3.4 - */ - public StrBuilder append(final CharBuffer buf, final int startIndex, final int length) { - if (buf == null) { - return appendNull(); - } - if (buf.hasArray()) { - final int totalLength = buf.remaining(); - if (startIndex < 0 || startIndex > totalLength) { - throw new StringIndexOutOfBoundsException("startIndex must be valid"); - } - if (length < 0 || (startIndex + length) > totalLength) { - throw new StringIndexOutOfBoundsException("length must be valid"); - } - final int len = length(); - ensureCapacity(len + length); - System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length); - size += length; - } else { - append(buf.toString(), startIndex, length); - } - return this; - } - - /** - * Appends a string buffer to this string builder. Appending null will call - * {@link #appendNull()}. - * - * @param str the string buffer to append - * @return this, to enable chaining - */ - public StrBuilder append(final StringBuffer str) { - if (str == null) { - return appendNull(); - } - final int strLen = str.length(); - if (strLen > 0) { - final int len = length(); - ensureCapacity(len + strLen); - str.getChars(0, strLen, buffer, len); - size += strLen; - } - return this; - } - - /** - * Appends part of a string buffer to this string builder. Appending null will - * call {@link #appendNull()}. - * - * @param str the string to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - */ - public StrBuilder append(final StringBuffer str, final int startIndex, final int length) { - if (str == null) { - return appendNull(); - } - if (startIndex < 0 || startIndex > str.length()) { - throw new StringIndexOutOfBoundsException("startIndex must be valid"); - } - if (length < 0 || (startIndex + length) > str.length()) { - throw new StringIndexOutOfBoundsException("length must be valid"); - } - if (length > 0) { - final int len = length(); - ensureCapacity(len + length); - str.getChars(startIndex, startIndex + length, buffer, len); - size += length; - } - return this; - } - - /** - * Appends a StringBuilder to this string builder. Appending null will call - * {@link #appendNull()}. - * - * @param str the StringBuilder to append - * @return this, to enable chaining - * @since 3.2 - */ - public StrBuilder append(final StringBuilder str) { - if (str == null) { - return appendNull(); - } - final int strLen = str.length(); - if (strLen > 0) { - final int len = length(); - ensureCapacity(len + strLen); - str.getChars(0, strLen, buffer, len); - size += strLen; - } - return this; - } - - /** - * Appends part of a StringBuilder to this string builder. Appending null will - * call {@link #appendNull()}. - * - * @param str the StringBuilder to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - * @since 3.2 - */ - public StrBuilder append(final StringBuilder str, final int startIndex, final int length) { - if (str == null) { - return appendNull(); - } - if (startIndex < 0 || startIndex > str.length()) { - throw new StringIndexOutOfBoundsException("startIndex must be valid"); - } - if (length < 0 || (startIndex + length) > str.length()) { - throw new StringIndexOutOfBoundsException("length must be valid"); - } - if (length > 0) { - final int len = length(); - ensureCapacity(len + length); - str.getChars(startIndex, startIndex + length, buffer, len); - size += length; - } - return this; - } - - /** - * Appends another string builder to this string builder. Appending null will - * call {@link #appendNull()}. - * - * @param str the string builder to append - * @return this, to enable chaining - */ - public StrBuilder append(final StrBuilder str) { - if (str == null) { - return appendNull(); - } - final int strLen = str.length(); - if (strLen > 0) { - final int len = length(); - ensureCapacity(len + strLen); - System.arraycopy(str.buffer, 0, buffer, len, strLen); - size += strLen; - } - return this; - } - - /** - * Appends part of a string builder to this string builder. Appending null will - * call {@link #appendNull()}. - * - * @param str the string to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - */ - public StrBuilder append(final StrBuilder str, final int startIndex, final int length) { - if (str == null) { - return appendNull(); - } - if (startIndex < 0 || startIndex > str.length()) { - throw new StringIndexOutOfBoundsException("startIndex must be valid"); - } - if (length < 0 || (startIndex + length) > str.length()) { - throw new StringIndexOutOfBoundsException("length must be valid"); - } - if (length > 0) { - final int len = length(); - ensureCapacity(len + length); - str.getChars(startIndex, startIndex + length, buffer, len); - size += length; - } - return this; - } - - /** - * Appends a char array to the string builder. Appending null will call - * {@link #appendNull()}. - * - * @param chars the char array to append - * @return this, to enable chaining - */ - public StrBuilder append(final char[] chars) { - if (chars == null) { - return appendNull(); - } - final int strLen = chars.length; - if (strLen > 0) { - final int len = length(); - ensureCapacity(len + strLen); - System.arraycopy(chars, 0, buffer, len, strLen); - size += strLen; - } - return this; - } - - /** - * Appends a char array to the string builder. Appending null will call - * {@link #appendNull()}. - * - * @param chars the char array to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - */ - public StrBuilder append(final char[] chars, final int startIndex, final int length) { - if (chars == null) { - return appendNull(); - } - if (startIndex < 0 || startIndex > chars.length) { - throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length); - } - if (length < 0 || (startIndex + length) > chars.length) { - throw new StringIndexOutOfBoundsException("Invalid length: " + length); - } - if (length > 0) { - final int len = length(); - ensureCapacity(len + length); - System.arraycopy(chars, startIndex, buffer, len, length); - size += length; - } - return this; - } - - /** - * Appends a boolean value to the string builder. - * - * @param value the value to append - * @return this, to enable chaining - */ - public StrBuilder append(final boolean value) { - if (value) { - ensureCapacity(size + 4); - buffer[size++] = 't'; - buffer[size++] = 'r'; - buffer[size++] = 'u'; - buffer[size++] = 'e'; - } else { - ensureCapacity(size + 5); - buffer[size++] = 'f'; - buffer[size++] = 'a'; - buffer[size++] = 'l'; - buffer[size++] = 's'; - buffer[size++] = 'e'; - } - return this; - } - - /** - * Appends a char value to the string builder. - * - * @param ch the value to append - * @return this, to enable chaining - * @since 3.0 - */ - @Override - public StrBuilder append(final char ch) { - final int len = length(); - ensureCapacity(len + 1); - buffer[size++] = ch; - return this; - } - - /** - * Appends an int value to the string builder using {@code String.valueOf}. - * - * @param value the value to append - * @return this, to enable chaining - */ - public StrBuilder append(final int value) { - return append(String.valueOf(value)); - } - - /** - * Appends a long value to the string builder using {@code String.valueOf}. - * - * @param value the value to append - * @return this, to enable chaining - */ - public StrBuilder append(final long value) { - return append(String.valueOf(value)); - } - - /** - * Appends a float value to the string builder using {@code String.valueOf}. - * - * @param value the value to append - * @return this, to enable chaining - */ - public StrBuilder append(final float value) { - return append(String.valueOf(value)); - } - - /** - * Appends a double value to the string builder using {@code String.valueOf}. - * - * @param value the value to append - * @return this, to enable chaining - */ - public StrBuilder append(final double value) { - return append(String.valueOf(value)); - } - - // ----------------------------------------------------------------------- - /** - * Appends an object followed by a new line to this string builder. Appending - * null will call {@link #appendNull()}. - * - * @param obj the object to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final Object obj) { - return append(obj).appendNewLine(); - } - - /** - * Appends a string followed by a new line to this string builder. Appending - * null will call {@link #appendNull()}. - * - * @param str the string to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final String str) { - return append(str).appendNewLine(); - } - - /** - * Appends part of a string followed by a new line to this string builder. - * Appending null will call {@link #appendNull()}. - * - * @param str the string to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final String str, final int startIndex, final int length) { - return append(str, startIndex, length).appendNewLine(); - } - - /** - * Calls {@link String#format(String, Object...)} and appends the result. - * - * @param format the format string - * @param objs the objects to use in the format string - * @return {@code this} to enable chaining - * @see String#format(String, Object...) - * @since 3.2 - */ - public StrBuilder appendln(final String format, final Object... objs) { - return append(format, objs).appendNewLine(); - } - - /** - * Appends a string buffer followed by a new line to this string builder. - * Appending null will call {@link #appendNull()}. - * - * @param str the string buffer to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final StringBuffer str) { - return append(str).appendNewLine(); - } - - /** - * Appends a string builder followed by a new line to this string builder. - * Appending null will call {@link #appendNull()}. - * - * @param str the string builder to append - * @return this, to enable chaining - * @since 3.2 - */ - public StrBuilder appendln(final StringBuilder str) { - return append(str).appendNewLine(); - } - - /** - * Appends part of a string builder followed by a new line to this string - * builder. Appending null will call {@link #appendNull()}. - * - * @param str the string builder to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - * @since 3.2 - */ - public StrBuilder appendln(final StringBuilder str, final int startIndex, final int length) { - return append(str, startIndex, length).appendNewLine(); - } - - /** - * Appends part of a string buffer followed by a new line to this string - * builder. Appending null will call {@link #appendNull()}. - * - * @param str the string to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final StringBuffer str, final int startIndex, final int length) { - return append(str, startIndex, length).appendNewLine(); - } - - /** - * Appends another string builder followed by a new line to this string builder. - * Appending null will call {@link #appendNull()}. - * - * @param str the string builder to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final StrBuilder str) { - return append(str).appendNewLine(); - } - - /** - * Appends part of a string builder followed by a new line to this string - * builder. Appending null will call {@link #appendNull()}. - * - * @param str the string to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final StrBuilder str, final int startIndex, final int length) { - return append(str, startIndex, length).appendNewLine(); - } - - /** - * Appends a char array followed by a new line to the string builder. Appending - * null will call {@link #appendNull()}. - * - * @param chars the char array to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final char[] chars) { - return append(chars).appendNewLine(); - } - - /** - * Appends a char array followed by a new line to the string builder. Appending - * null will call {@link #appendNull()}. - * - * @param chars the char array to append - * @param startIndex the start index, inclusive, must be valid - * @param length the length to append, must be valid - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final char[] chars, final int startIndex, final int length) { - return append(chars, startIndex, length).appendNewLine(); - } - - /** - * Appends a boolean value followed by a new line to the string builder. - * - * @param value the value to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final boolean value) { - return append(value).appendNewLine(); - } - - /** - * Appends a char value followed by a new line to the string builder. - * - * @param ch the value to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final char ch) { - return append(ch).appendNewLine(); - } - - /** - * Appends an int value followed by a new line to the string builder using - * {@code String.valueOf}. - * - * @param value the value to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final int value) { - return append(value).appendNewLine(); - } - - /** - * Appends a long value followed by a new line to the string builder using - * {@code String.valueOf}. - * - * @param value the value to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final long value) { - return append(value).appendNewLine(); - } - - /** - * Appends a float value followed by a new line to the string builder using - * {@code String.valueOf}. - * - * @param value the value to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final float value) { - return append(value).appendNewLine(); - } - - /** - * Appends a double value followed by a new line to the string builder using - * {@code String.valueOf}. - * - * @param value the value to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendln(final double value) { - return append(value).appendNewLine(); - } - - // ----------------------------------------------------------------------- - /** - * Appends each item in an array to the builder without any separators. - * Appending a null array will have no effect. Each object is appended using - * {@link #append(Object)}. - * - * @param the element type - * @param array the array to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendAll(@SuppressWarnings("unchecked") final T... array) { - /* - * @SuppressWarnings used to hide warning about vararg usage. We cannot - * use @SafeVarargs, since this method is not final. Using @SuppressWarnings is - * fine, because it isn't inherited by subclasses, so each subclass must vouch - * for itself whether its use of 'array' is safe. - */ - if (array.length > 0) { - for (final Object element : array) { - append(element); - } - } - return this; - } - - /** - * Appends each item in an iterable to the builder without any separators. - * Appending a null iterable will have no effect. Each object is appended using - * {@link #append(Object)}. - * - * @param iterable the iterable to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendAll(final Iterable iterable) { - if (iterable != null) { - for (final Object o : iterable) { - append(o); - } - } - return this; - } - - /** - * Appends each item in an iterator to the builder without any separators. - * Appending a null iterator will have no effect. Each object is appended using - * {@link #append(Object)}. - * - * @param it the iterator to append - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendAll(final Iterator it) { - if (it != null) { - while (it.hasNext()) { - append(it.next()); - } - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Appends an array placing separators between each value, but not before the - * first or after the last. Appending a null array will have no effect. Each - * object is appended using {@link #append(Object)}. - * - * @param array the array to append - * @param separator the separator to use, null means no separator - * @return this, to enable chaining - */ - public StrBuilder appendWithSeparators(final Object[] array, final String separator) { - if (array != null && array.length > 0) { - final String sep = Objects.toString(separator, ""); - append(array[0]); - for (int i = 1; i < array.length; i++) { - append(sep); - append(array[i]); - } - } - return this; - } - - /** - * Appends an iterable placing separators between each value, but not before the - * first or after the last. Appending a null iterable will have no effect. Each - * object is appended using {@link #append(Object)}. - * - * @param iterable the iterable to append - * @param separator the separator to use, null means no separator - * @return this, to enable chaining - */ - public StrBuilder appendWithSeparators(final Iterable iterable, final String separator) { - if (iterable != null) { - final String sep = Objects.toString(separator, ""); - final Iterator it = iterable.iterator(); - while (it.hasNext()) { - append(it.next()); - if (it.hasNext()) { - append(sep); - } - } - } - return this; - } - - /** - * Appends an iterator placing separators between each value, but not before the - * first or after the last. Appending a null iterator will have no effect. Each - * object is appended using {@link #append(Object)}. - * - * @param it the iterator to append - * @param separator the separator to use, null means no separator - * @return this, to enable chaining - */ - public StrBuilder appendWithSeparators(final Iterator it, final String separator) { - if (it != null) { - final String sep = Objects.toString(separator, ""); - while (it.hasNext()) { - append(it.next()); - if (it.hasNext()) { - append(sep); - } - } - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Appends a separator if the builder is currently non-empty. Appending a null - * separator will have no effect. The separator is appended using - * {@link #append(String)}. - *

- * This method is useful for adding a separator each time around the loop except - * the first. - * - *

-	 * for (Iterator it = list.iterator(); it.hasNext();) {
-	 * 	appendSeparator(",");
-	 * 	append(it.next());
-	 * }
-	 * 
- * - * Note that for this simple example, you should use - * {@link #appendWithSeparators(Iterable, String)}. - * - * @param separator the separator to use, null means no separator - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendSeparator(final String separator) { - return appendSeparator(separator, null); - } - - /** - * Appends one of both separators to the StrBuilder. If the builder is currently - * empty it will append the defaultIfEmpty-separator Otherwise it will append - * the standard-separator - * - * Appending a null separator will have no effect. The separator is appended - * using {@link #append(String)}. - *

- * This method is for example useful for constructing queries - * - *

-	 * StrBuilder whereClause = new StrBuilder();
-	 * if (searchCommand.getPriority() != null) {
-	 *  whereClause.appendSeparator(" and", " where");
-	 *  whereClause.append(" priority = ?")
-	 * }
-	 * if (searchCommand.getComponent() != null) {
-	 *  whereClause.appendSeparator(" and", " where");
-	 *  whereClause.append(" component = ?")
-	 * }
-	 * selectClause.append(whereClause)
-	 * 
- * - * @param standard the separator if builder is not empty, null means no - * separator - * @param defaultIfEmpty the separator if builder is empty, null means no - * separator - * @return this, to enable chaining - * @since 2.5 - */ - public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) { - final String str = isEmpty() ? defaultIfEmpty : standard; - if (str != null) { - append(str); - } - return this; - } - - /** - * Appends a separator if the builder is currently non-empty. The separator is - * appended using {@link #append(char)}. - *

- * This method is useful for adding a separator each time around the loop except - * the first. - * - *

-	 * for (Iterator it = list.iterator(); it.hasNext();) {
-	 * 	appendSeparator(',');
-	 * 	append(it.next());
-	 * }
-	 * 
- * - * Note that for this simple example, you should use - * {@link #appendWithSeparators(Iterable, String)}. - * - * @param separator the separator to use - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendSeparator(final char separator) { - if (isNotEmpty()) { - append(separator); - } - return this; - } - - /** - * Append one of both separators to the builder If the builder is currently - * empty it will append the defaultIfEmpty-separator Otherwise it will append - * the standard-separator - * - * The separator is appended using {@link #append(char)}. - * - * @param standard the separator if builder is not empty - * @param defaultIfEmpty the separator if builder is empty - * @return this, to enable chaining - * @since 2.5 - */ - public StrBuilder appendSeparator(final char standard, final char defaultIfEmpty) { - if (isNotEmpty()) { - append(standard); - } else { - append(defaultIfEmpty); - } - return this; - } - - /** - * Appends a separator to the builder if the loop index is greater than zero. - * Appending a null separator will have no effect. The separator is appended - * using {@link #append(String)}. - *

- * This method is useful for adding a separator each time around the loop except - * the first. - *

- * - *
-	 * for (int i = 0; i < list.size(); i++) {
-	 * 	appendSeparator(",", i);
-	 * 	append(list.get(i));
-	 * }
-	 * 
- * - * Note that for this simple example, you should use - * {@link #appendWithSeparators(Iterable, String)}. - * - * @param separator the separator to use, null means no separator - * @param loopIndex the loop index - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendSeparator(final String separator, final int loopIndex) { - if (separator != null && loopIndex > 0) { - append(separator); - } - return this; - } - - /** - * Appends a separator to the builder if the loop index is greater than zero. - * The separator is appended using {@link #append(char)}. - *

- * This method is useful for adding a separator each time around the loop except - * the first. - *

- * - *
-	 * for (int i = 0; i < list.size(); i++) {
-	 * 	appendSeparator(",", i);
-	 * 	append(list.get(i));
-	 * }
-	 * 
- * - * Note that for this simple example, you should use - * {@link #appendWithSeparators(Iterable, String)}. - * - * @param separator the separator to use - * @param loopIndex the loop index - * @return this, to enable chaining - * @since 2.3 - */ - public StrBuilder appendSeparator(final char separator, final int loopIndex) { - if (loopIndex > 0) { - append(separator); - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Appends the pad character to the builder the specified number of times. - * - * @param length the length to append, negative means no append - * @param padChar the character to append - * @return this, to enable chaining - */ - public StrBuilder appendPadding(final int length, final char padChar) { - if (length >= 0) { - ensureCapacity(size + length); - for (int i = 0; i < length; i++) { - buffer[size++] = padChar; - } - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Appends an object to the builder padding on the left to a fixed width. The - * {@code toString} of the object is used. If the object is larger than the - * length, the left hand side is lost. If the object is null, the null text - * value is used. - * - * @param obj the object to append, null uses null text - * @param width the fixed field width, zero or negative has no effect - * @param padChar the pad character to use - * @return this, to enable chaining - */ - public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) { - if (width > 0) { - ensureCapacity(size + width); - String str = (obj == null ? getNullText() : obj.toString()); - if (str == null) { - str = StringUtils.EMPTY; - } - final int strLen = str.length(); - if (strLen >= width) { - str.getChars(strLen - width, strLen, buffer, size); - } else { - final int padLen = width - strLen; - for (int i = 0; i < padLen; i++) { - buffer[size + i] = padChar; - } - str.getChars(0, strLen, buffer, size + padLen); - } - size += width; - } - return this; - } - - /** - * Appends an object to the builder padding on the left to a fixed width. The - * {@code String.valueOf} of the {@code int} value is used. If the formatted - * value is larger than the length, the left hand side is lost. - * - * @param value the value to append - * @param width the fixed field width, zero or negative has no effect - * @param padChar the pad character to use - * @return this, to enable chaining - */ - public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) { - return appendFixedWidthPadLeft(String.valueOf(value), width, padChar); - } - - /** - * Appends an object to the builder padding on the right to a fixed length. The - * {@code toString} of the object is used. If the object is larger than the - * length, the right hand side is lost. If the object is null, null text value - * is used. - * - * @param obj the object to append, null uses null text - * @param width the fixed field width, zero or negative has no effect - * @param padChar the pad character to use - * @return this, to enable chaining - */ - public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) { - if (width > 0) { - ensureCapacity(size + width); - String str = (obj == null ? getNullText() : obj.toString()); - if (str == null) { - str = StringUtils.EMPTY; - } - final int strLen = str.length(); - if (strLen >= width) { - str.getChars(0, width, buffer, size); - } else { - final int padLen = width - strLen; - str.getChars(0, strLen, buffer, size); - for (int i = 0; i < padLen; i++) { - buffer[size + strLen + i] = padChar; - } - } - size += width; - } - return this; - } - - /** - * Appends an object to the builder padding on the right to a fixed length. The - * {@code String.valueOf} of the {@code int} value is used. If the object is - * larger than the length, the right hand side is lost. - * - * @param value the value to append - * @param width the fixed field width, zero or negative has no effect - * @param padChar the pad character to use - * @return this, to enable chaining - */ - public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) { - return appendFixedWidthPadRight(String.valueOf(value), width, padChar); - } - - // ----------------------------------------------------------------------- - /** - * Inserts the string representation of an object into this builder. Inserting - * null will use the stored null text value. - * - * @param index the index to add at, must be valid - * @param obj the object to insert - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder insert(final int index, final Object obj) { - if (obj == null) { - return insert(index, nullText); - } - return insert(index, obj.toString()); - } - - /** - * Inserts the string into this builder. Inserting null will use the stored null - * text value. - * - * @param index the index to add at, must be valid - * @param str the string to insert - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder insert(final int index, String str) { - validateIndex(index); - if (str == null) { - str = nullText; - } - if (str != null) { - final int strLen = str.length(); - if (strLen > 0) { - final int newSize = size + strLen; - ensureCapacity(newSize); - System.arraycopy(buffer, index, buffer, index + strLen, size - index); - size = newSize; - str.getChars(0, strLen, buffer, index); - } - } - return this; - } - - /** - * Inserts the character array into this builder. Inserting null will use the - * stored null text value. - * - * @param index the index to add at, must be valid - * @param chars the char array to insert - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder insert(final int index, final char[] chars) { - validateIndex(index); - if (chars == null) { - return insert(index, nullText); - } - final int len = chars.length; - if (len > 0) { - ensureCapacity(size + len); - System.arraycopy(buffer, index, buffer, index + len, size - index); - System.arraycopy(chars, 0, buffer, index, len); - size += len; - } - return this; - } - - /** - * Inserts part of the character array into this builder. Inserting null will - * use the stored null text value. - * - * @param index the index to add at, must be valid - * @param chars the char array to insert - * @param offset the offset into the character array to start at, must be valid - * @param length the length of the character array part to copy, must be - * positive - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if any index is invalid - */ - public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) { - validateIndex(index); - if (chars == null) { - return insert(index, nullText); - } - if (offset < 0 || offset > chars.length) { - throw new StringIndexOutOfBoundsException("Invalid offset: " + offset); - } - if (length < 0 || offset + length > chars.length) { - throw new StringIndexOutOfBoundsException("Invalid length: " + length); - } - if (length > 0) { - ensureCapacity(size + length); - System.arraycopy(buffer, index, buffer, index + length, size - index); - System.arraycopy(chars, offset, buffer, index, length); - size += length; - } - return this; - } - - /** - * Inserts the value into this builder. - * - * @param index the index to add at, must be valid - * @param value the value to insert - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder insert(int index, final boolean value) { - validateIndex(index); - if (value) { - ensureCapacity(size + 4); - System.arraycopy(buffer, index, buffer, index + 4, size - index); - buffer[index++] = 't'; - buffer[index++] = 'r'; - buffer[index++] = 'u'; - buffer[index] = 'e'; - size += 4; - } else { - ensureCapacity(size + 5); - System.arraycopy(buffer, index, buffer, index + 5, size - index); - buffer[index++] = 'f'; - buffer[index++] = 'a'; - buffer[index++] = 'l'; - buffer[index++] = 's'; - buffer[index] = 'e'; - size += 5; - } - return this; - } - - /** - * Inserts the value into this builder. - * - * @param index the index to add at, must be valid - * @param value the value to insert - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder insert(final int index, final char value) { - validateIndex(index); - ensureCapacity(size + 1); - System.arraycopy(buffer, index, buffer, index + 1, size - index); - buffer[index] = value; - size++; - return this; - } - - /** - * Inserts the value into this builder. - * - * @param index the index to add at, must be valid - * @param value the value to insert - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder insert(final int index, final int value) { - return insert(index, String.valueOf(value)); - } - - /** - * Inserts the value into this builder. - * - * @param index the index to add at, must be valid - * @param value the value to insert - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder insert(final int index, final long value) { - return insert(index, String.valueOf(value)); - } - - /** - * Inserts the value into this builder. - * - * @param index the index to add at, must be valid - * @param value the value to insert - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder insert(final int index, final float value) { - return insert(index, String.valueOf(value)); - } - - /** - * Inserts the value into this builder. - * - * @param index the index to add at, must be valid - * @param value the value to insert - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder insert(final int index, final double value) { - return insert(index, String.valueOf(value)); - } - - // ----------------------------------------------------------------------- - /** - * Internal method to delete a range without validation. - * - * @param startIndex the start index, must be valid - * @param endIndex the end index (exclusive), must be valid - * @param len the length, must be valid - * @throws IndexOutOfBoundsException if any index is invalid - */ - private void deleteImpl(final int startIndex, final int endIndex, final int len) { - System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex); - size -= len; - } - - /** - * Deletes the characters between the two specified indices. - * - * @param startIndex the start index, inclusive, must be valid - * @param endIndex the end index, exclusive, must be valid except that if too - * large it is treated as end of string - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder delete(final int startIndex, int endIndex) { - endIndex = validateRange(startIndex, endIndex); - final int len = endIndex - startIndex; - if (len > 0) { - deleteImpl(startIndex, endIndex, len); - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Deletes the character wherever it occurs in the builder. - * - * @param ch the character to delete - * @return this, to enable chaining - */ - public StrBuilder deleteAll(final char ch) { - for (int i = 0; i < size; i++) { - if (buffer[i] == ch) { - final int start = i; - while (++i < size) { - if (buffer[i] != ch) { - break; - } - } - final int len = i - start; - deleteImpl(start, i, len); - i -= len; - } - } - return this; - } - - /** - * Deletes the character wherever it occurs in the builder. - * - * @param ch the character to delete - * @return this, to enable chaining - */ - public StrBuilder deleteFirst(final char ch) { - for (int i = 0; i < size; i++) { - if (buffer[i] == ch) { - deleteImpl(i, i + 1, 1); - break; - } - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Deletes the string wherever it occurs in the builder. - * - * @param str the string to delete, null causes no action - * @return this, to enable chaining - */ - public StrBuilder deleteAll(final String str) { - final int len = (str == null ? 0 : str.length()); - if (len > 0) { - int index = indexOf(str, 0); - while (index >= 0) { - deleteImpl(index, index + len, len); - index = indexOf(str, index); - } - } - return this; - } - - /** - * Deletes the string wherever it occurs in the builder. - * - * @param str the string to delete, null causes no action - * @return this, to enable chaining - */ - public StrBuilder deleteFirst(final String str) { - final int len = (str == null ? 0 : str.length()); - if (len > 0) { - final int index = indexOf(str, 0); - if (index >= 0) { - deleteImpl(index, index + len, len); - } - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Deletes all parts of the builder that the matcher matches. - *

- * Matchers can be used to perform advanced deletion behavior. For example you - * could write a matcher to delete all occurrences where the character 'a' is - * followed by a number. - * - * @param matcher the matcher to use to find the deletion, null causes no action - * @return this, to enable chaining - */ - public StrBuilder deleteAll(final StrMatcher matcher) { - return replace(matcher, null, 0, size, -1); - } - - /** - * Deletes the first match within the builder using the specified matcher. - *

- * Matchers can be used to perform advanced deletion behavior. For example you - * could write a matcher to delete where the character 'a' is followed by a - * number. - * - * @param matcher the matcher to use to find the deletion, null causes no action - * @return this, to enable chaining - */ - public StrBuilder deleteFirst(final StrMatcher matcher) { - return replace(matcher, null, 0, size, 1); - } - - // ----------------------------------------------------------------------- - /** - * Internal method to delete a range without validation. - * - * @param startIndex the start index, must be valid - * @param endIndex the end index (exclusive), must be valid - * @param removeLen the length to remove (endIndex - startIndex), must be valid - * @param insertStr the string to replace with, null means delete range - * @param insertLen the length of the insert string, must be valid - * @throws IndexOutOfBoundsException if any index is invalid - */ - private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, - final int insertLen) { - final int newSize = size - removeLen + insertLen; - if (insertLen != removeLen) { - ensureCapacity(newSize); - System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex); - size = newSize; - } - if (insertLen > 0) { - insertStr.getChars(0, insertLen, buffer, startIndex); - } - } - - /** - * Replaces a portion of the string builder with another string. The length of - * the inserted string does not have to match the removed length. - * - * @param startIndex the start index, inclusive, must be valid - * @param endIndex the end index, exclusive, must be valid except that if too - * large it is treated as end of string - * @param replaceStr the string to replace with, null means delete range - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if the index is invalid - */ - public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) { - endIndex = validateRange(startIndex, endIndex); - final int insertLen = (replaceStr == null ? 0 : replaceStr.length()); - replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen); - return this; - } - - // ----------------------------------------------------------------------- - /** - * Replaces the search character with the replace character throughout the - * builder. - * - * @param search the search character - * @param replace the replace character - * @return this, to enable chaining - */ - public StrBuilder replaceAll(final char search, final char replace) { - if (search != replace) { - for (int i = 0; i < size; i++) { - if (buffer[i] == search) { - buffer[i] = replace; - } - } - } - return this; - } - - /** - * Replaces the first instance of the search character with the replace - * character in the builder. - * - * @param search the search character - * @param replace the replace character - * @return this, to enable chaining - */ - public StrBuilder replaceFirst(final char search, final char replace) { - if (search != replace) { - for (int i = 0; i < size; i++) { - if (buffer[i] == search) { - buffer[i] = replace; - break; - } - } - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Replaces the search string with the replace string throughout the builder. - * - * @param searchStr the search string, null causes no action to occur - * @param replaceStr the replace string, null is equivalent to an empty string - * @return this, to enable chaining - */ - public StrBuilder replaceAll(final String searchStr, final String replaceStr) { - final int searchLen = (searchStr == null ? 0 : searchStr.length()); - if (searchLen > 0) { - final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); - int index = indexOf(searchStr, 0); - while (index >= 0) { - replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); - index = indexOf(searchStr, index + replaceLen); - } - } - return this; - } - - /** - * Replaces the first instance of the search string with the replace string. - * - * @param searchStr the search string, null causes no action to occur - * @param replaceStr the replace string, null is equivalent to an empty string - * @return this, to enable chaining - */ - public StrBuilder replaceFirst(final String searchStr, final String replaceStr) { - final int searchLen = (searchStr == null ? 0 : searchStr.length()); - if (searchLen > 0) { - final int index = indexOf(searchStr, 0); - if (index >= 0) { - final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); - replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); - } - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Replaces all matches within the builder with the replace string. - *

- * Matchers can be used to perform advanced replace behavior. For example you - * could write a matcher to replace all occurrences where the character 'a' is - * followed by a number. - * - * @param matcher the matcher to use to find the deletion, null causes no - * action - * @param replaceStr the replace string, null is equivalent to an empty string - * @return this, to enable chaining - */ - public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) { - return replace(matcher, replaceStr, 0, size, -1); - } - - /** - * Replaces the first match within the builder with the replace string. - *

- * Matchers can be used to perform advanced replace behavior. For example you - * could write a matcher to replace where the character 'a' is followed by a - * number. - * - * @param matcher the matcher to use to find the deletion, null causes no - * action - * @param replaceStr the replace string, null is equivalent to an empty string - * @return this, to enable chaining - */ - public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) { - return replace(matcher, replaceStr, 0, size, 1); - } - - // ----------------------------------------------------------------------- - /** - * Advanced search and replaces within the builder using a matcher. - *

- * Matchers can be used to perform advanced behavior. For example you could - * write a matcher to delete all occurrences where the character 'a' is followed - * by a number. - * - * @param matcher the matcher to use to find the deletion, null causes no - * action - * @param replaceStr the string to replace the match with, null is a delete - * @param startIndex the start index, inclusive, must be valid - * @param endIndex the end index, exclusive, must be valid except that if - * too large it is treated as end of string - * @param replaceCount the number of times to replace, -1 for replace all - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if start index is invalid - */ - public StrBuilder replace(final StrMatcher matcher, final String replaceStr, final int startIndex, int endIndex, - final int replaceCount) { - endIndex = validateRange(startIndex, endIndex); - return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount); - } - - /** - * Replaces within the builder using a matcher. - *

- * Matchers can be used to perform advanced behavior. For example you could - * write a matcher to delete all occurrences where the character 'a' is followed - * by a number. - * - * @param matcher the matcher to use to find the deletion, null causes no - * action - * @param replaceStr the string to replace the match with, null is a delete - * @param from the start index, must be valid - * @param to the end index (exclusive), must be valid - * @param replaceCount the number of times to replace, -1 for replace all - * @return this, to enable chaining - * @throws IndexOutOfBoundsException if any index is invalid - */ - private StrBuilder replaceImpl(final StrMatcher matcher, final String replaceStr, final int from, int to, - int replaceCount) { - if (matcher == null || size == 0) { - return this; - } - final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); - for (int i = from; i < to && replaceCount != 0; i++) { - final char[] buf = buffer; - final int removeLen = matcher.isMatch(buf, i, from, to); - if (removeLen > 0) { - replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen); - to = to - removeLen + replaceLen; - i = i + replaceLen - 1; - if (replaceCount > 0) { - replaceCount--; - } - } - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Reverses the string builder placing each character in the opposite index. - * - * @return this, to enable chaining - */ - public StrBuilder reverse() { - if (size == 0) { - return this; - } - - final int half = size / 2; - final char[] buf = buffer; - for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) { - final char swap = buf[leftIdx]; - buf[leftIdx] = buf[rightIdx]; - buf[rightIdx] = swap; - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Trims the builder by removing characters less than or equal to a space from - * the beginning and end. - * - * @return this, to enable chaining - */ - public StrBuilder trim() { - if (size == 0) { - return this; - } - int len = size; - final char[] buf = buffer; - int pos = 0; - while (pos < len && buf[pos] <= ' ') { - pos++; - } - while (pos < len && buf[len - 1] <= ' ') { - len--; - } - if (len < size) { - delete(len, size); - } - if (pos > 0) { - delete(0, pos); - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Checks whether this builder starts with the specified string. - *

- * Note that this method handles null input quietly, unlike String. - * - * @param str the string to search for, null returns false - * @return true if the builder starts with the string - */ - public boolean startsWith(final String str) { - if (str == null) { - return false; - } - final int len = str.length(); - if (len == 0) { - return true; - } - if (len > size) { - return false; - } - for (int i = 0; i < len; i++) { - if (buffer[i] != str.charAt(i)) { - return false; - } - } - return true; - } - - /** - * Checks whether this builder ends with the specified string. - *

- * Note that this method handles null input quietly, unlike String. - * - * @param str the string to search for, null returns false - * @return true if the builder ends with the string - */ - public boolean endsWith(final String str) { - if (str == null) { - return false; - } - final int len = str.length(); - if (len == 0) { - return true; - } - if (len > size) { - return false; - } - int pos = size - len; - for (int i = 0; i < len; i++, pos++) { - if (buffer[pos] != str.charAt(i)) { - return false; - } - } - return true; - } - - // ----------------------------------------------------------------------- - /** - * {@inheritDoc} - * - * @since 3.0 - */ - @Override - public CharSequence subSequence(final int startIndex, final int endIndex) { - if (startIndex < 0) { - throw new StringIndexOutOfBoundsException(startIndex); - } - if (endIndex > size) { - throw new StringIndexOutOfBoundsException(endIndex); - } - if (startIndex > endIndex) { - throw new StringIndexOutOfBoundsException(endIndex - startIndex); - } - return substring(startIndex, endIndex); - } - - /** - * Extracts a portion of this string builder as a string. - * - * @param start the start index, inclusive, must be valid - * @return the new string - * @throws IndexOutOfBoundsException if the index is invalid - */ - public String substring(final int start) { - return substring(start, size); - } - - /** - * Extracts a portion of this string builder as a string. - *

- * Note: This method treats an endIndex greater than the length of the builder - * as equal to the length of the builder, and continues without error, unlike - * StringBuffer or String. - * - * @param startIndex the start index, inclusive, must be valid - * @param endIndex the end index, exclusive, must be valid except that if too - * large it is treated as end of string - * @return the new string - * @throws IndexOutOfBoundsException if the index is invalid - */ - public String substring(final int startIndex, int endIndex) { - endIndex = validateRange(startIndex, endIndex); - return new String(buffer, startIndex, endIndex - startIndex); - } - - /** - * Extracts the leftmost characters from the string builder without throwing an - * exception. - *

- * This method extracts the left {@code length} characters from the builder. If - * this many characters are not available, the whole builder is returned. Thus - * the returned string may be shorter than the length requested. - * - * @param length the number of characters to extract, negative returns empty - * string - * @return the new string - */ - public String leftString(final int length) { - if (length <= 0) { - return StringUtils.EMPTY; - } else if (length >= size) { - return new String(buffer, 0, size); - } else { - return new String(buffer, 0, length); - } - } - - /** - * Extracts the rightmost characters from the string builder without throwing an - * exception. - *

- * This method extracts the right {@code length} characters from the builder. If - * this many characters are not available, the whole builder is returned. Thus - * the returned string may be shorter than the length requested. - * - * @param length the number of characters to extract, negative returns empty - * string - * @return the new string - */ - public String rightString(final int length) { - if (length <= 0) { - return StringUtils.EMPTY; - } else if (length >= size) { - return new String(buffer, 0, size); - } else { - return new String(buffer, size - length, length); - } - } - - /** - * Extracts some characters from the middle of the string builder without - * throwing an exception. - *

- * This method extracts {@code length} characters from the builder at the - * specified index. If the index is negative it is treated as zero. If the index - * is greater than the builder size, it is treated as the builder size. If the - * length is negative, the empty string is returned. If insufficient characters - * are available in the builder, as much as possible is returned. Thus the - * returned string may be shorter than the length requested. - * - * @param index the index to start at, negative means zero - * @param length the number of characters to extract, negative returns empty - * string - * @return the new string - */ - public String midString(int index, final int length) { - if (index < 0) { - index = 0; - } - if (length <= 0 || index >= size) { - return StringUtils.EMPTY; - } - if (size <= index + length) { - return new String(buffer, index, size - index); - } - return new String(buffer, index, length); - } - - // ----------------------------------------------------------------------- - /** - * Checks if the string builder contains the specified char. - * - * @param ch the character to find - * @return true if the builder contains the character - */ - public boolean contains(final char ch) { - final char[] thisBuf = buffer; - for (int i = 0; i < this.size; i++) { - if (thisBuf[i] == ch) { - return true; - } - } - return false; - } - - /** - * Checks if the string builder contains the specified string. - * - * @param str the string to find - * @return true if the builder contains the string - */ - public boolean contains(final String str) { - return indexOf(str, 0) >= 0; - } - - /** - * Checks if the string builder contains a string matched using the specified - * matcher. - *

- * Matchers can be used to perform advanced searching behavior. For example you - * could write a matcher to search for the character 'a' followed by a number. - * - * @param matcher the matcher to use, null returns -1 - * @return true if the matcher finds a match in the builder - */ - public boolean contains(final StrMatcher matcher) { - return indexOf(matcher, 0) >= 0; - } - - // ----------------------------------------------------------------------- - /** - * Searches the string builder to find the first reference to the specified - * char. - * - * @param ch the character to find - * @return the first index of the character, or -1 if not found - */ - public int indexOf(final char ch) { - return indexOf(ch, 0); - } - - /** - * Searches the string builder to find the first reference to the specified - * char. - * - * @param ch the character to find - * @param startIndex the index to start at, invalid index rounded to edge - * @return the first index of the character, or -1 if not found - */ - public int indexOf(final char ch, int startIndex) { - startIndex = (Math.max(startIndex, 0)); - if (startIndex >= size) { - return -1; - } - final char[] thisBuf = buffer; - for (int i = startIndex; i < size; i++) { - if (thisBuf[i] == ch) { - return i; - } - } - return -1; - } - - /** - * Searches the string builder to find the first reference to the specified - * string. - *

- * Note that a null input string will return -1, whereas the JDK throws an - * exception. - * - * @param str the string to find, null returns -1 - * @return the first index of the string, or -1 if not found - */ - public int indexOf(final String str) { - return indexOf(str, 0); - } - - /** - * Searches the string builder to find the first reference to the specified - * string starting searching from the given index. - *

- * Note that a null input string will return -1, whereas the JDK throws an - * exception. - * - * @param str the string to find, null returns -1 - * @param startIndex the index to start at, invalid index rounded to edge - * @return the first index of the string, or -1 if not found - */ - public int indexOf(final String str, int startIndex) { - startIndex = (Math.max(startIndex, 0)); - if (str == null || startIndex >= size) { - return -1; - } - final int strLen = str.length(); - if (strLen == 1) { - return indexOf(str.charAt(0), startIndex); - } - if (strLen == 0) { - return startIndex; - } - if (strLen > size) { - return -1; - } - final char[] thisBuf = buffer; - final int len = size - strLen + 1; - outer: for (int i = startIndex; i < len; i++) { - for (int j = 0; j < strLen; j++) { - if (str.charAt(j) != thisBuf[i + j]) { - continue outer; - } - } - return i; - } - return -1; - } - - /** - * Searches the string builder using the matcher to find the first match. - *

- * Matchers can be used to perform advanced searching behavior. For example you - * could write a matcher to find the character 'a' followed by a number. - * - * @param matcher the matcher to use, null returns -1 - * @return the first index matched, or -1 if not found - */ - public int indexOf(final StrMatcher matcher) { - return indexOf(matcher, 0); - } - - /** - * Searches the string builder using the matcher to find the first match - * searching from the given index. - *

- * Matchers can be used to perform advanced searching behavior. For example you - * could write a matcher to find the character 'a' followed by a number. - * - * @param matcher the matcher to use, null returns -1 - * @param startIndex the index to start at, invalid index rounded to edge - * @return the first index matched, or -1 if not found - */ - public int indexOf(final StrMatcher matcher, int startIndex) { - startIndex = (Math.max(startIndex, 0)); - if (matcher == null || startIndex >= size) { - return -1; - } - final int len = size; - final char[] buf = buffer; - for (int i = startIndex; i < len; i++) { - if (matcher.isMatch(buf, i, startIndex, len) > 0) { - return i; - } - } - return -1; - } - - // ----------------------------------------------------------------------- - /** - * Searches the string builder to find the last reference to the specified char. - * - * @param ch the character to find - * @return the last index of the character, or -1 if not found - */ - public int lastIndexOf(final char ch) { - return lastIndexOf(ch, size - 1); - } - - /** - * Searches the string builder to find the last reference to the specified char. - * - * @param ch the character to find - * @param startIndex the index to start at, invalid index rounded to edge - * @return the last index of the character, or -1 if not found - */ - public int lastIndexOf(final char ch, int startIndex) { - startIndex = (startIndex >= size ? size - 1 : startIndex); - if (startIndex < 0) { - return -1; - } - for (int i = startIndex; i >= 0; i--) { - if (buffer[i] == ch) { - return i; - } - } - return -1; - } - - /** - * Searches the string builder to find the last reference to the specified - * string. - *

- * Note that a null input string will return -1, whereas the JDK throws an - * exception. - * - * @param str the string to find, null returns -1 - * @return the last index of the string, or -1 if not found - */ - public int lastIndexOf(final String str) { - return lastIndexOf(str, size - 1); - } - - /** - * Searches the string builder to find the last reference to the specified - * string starting searching from the given index. - *

- * Note that a null input string will return -1, whereas the JDK throws an - * exception. - * - * @param str the string to find, null returns -1 - * @param startIndex the index to start at, invalid index rounded to edge - * @return the last index of the string, or -1 if not found - */ - public int lastIndexOf(final String str, int startIndex) { - startIndex = (startIndex >= size ? size - 1 : startIndex); - if (str == null || startIndex < 0) { - return -1; - } - final int strLen = str.length(); - if (strLen > 0 && strLen <= size) { - if (strLen == 1) { - return lastIndexOf(str.charAt(0), startIndex); - } - - outer: for (int i = startIndex - strLen + 1; i >= 0; i--) { - for (int j = 0; j < strLen; j++) { - if (str.charAt(j) != buffer[i + j]) { - continue outer; - } - } - return i; - } - - } else if (strLen == 0) { - return startIndex; - } - return -1; - } - - /** - * Searches the string builder using the matcher to find the last match. - *

- * Matchers can be used to perform advanced searching behavior. For example you - * could write a matcher to find the character 'a' followed by a number. - * - * @param matcher the matcher to use, null returns -1 - * @return the last index matched, or -1 if not found - */ - public int lastIndexOf(final StrMatcher matcher) { - return lastIndexOf(matcher, size); - } - - /** - * Searches the string builder using the matcher to find the last match - * searching from the given index. - *

- * Matchers can be used to perform advanced searching behavior. For example you - * could write a matcher to find the character 'a' followed by a number. - * - * @param matcher the matcher to use, null returns -1 - * @param startIndex the index to start at, invalid index rounded to edge - * @return the last index matched, or -1 if not found - */ - public int lastIndexOf(final StrMatcher matcher, int startIndex) { - startIndex = (startIndex >= size ? size - 1 : startIndex); - if (matcher == null || startIndex < 0) { - return -1; - } - final char[] buf = buffer; - final int endIndex = startIndex + 1; - for (int i = startIndex; i >= 0; i--) { - if (matcher.isMatch(buf, i, 0, endIndex) > 0) { - return i; - } - } - return -1; - } - - // ----------------------------------------------------------------------- - /** - * Creates a tokenizer that can tokenize the contents of this builder. - *

- * This method allows the contents of this builder to be tokenized. The - * tokenizer will be setup by default to tokenize on space, tab, newline and - * formfeed (as per StringTokenizer). These values can be changed on the - * tokenizer class, before retrieving the tokens. - *

- * The returned tokenizer is linked to this builder. You may intermix calls to - * the builder and tokenizer within certain limits, however there is no - * synchronization. Once the tokenizer has been used once, it must be - * {@link StrTokenizer#reset() reset} to pickup the latest changes in the - * builder. For example: - * - *

-	 * StrBuilder b = new StrBuilder();
-	 * b.append("a b ");
-	 * StrTokenizer t = b.asTokenizer();
-	 * String[] tokens1 = t.getTokenArray(); // returns a,b
-	 * b.append("c d ");
-	 * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
-	 * t.reset(); // reset causes builder changes to be picked up
-	 * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
-	 * 
- * - * In addition to simply intermixing appends and tokenization, you can also call - * the set methods on the tokenizer to alter how it tokenizes. Just remember to - * call reset when you want to pickup builder changes. - *

- * Calling {@link StrTokenizer#reset(String)} or - * {@link StrTokenizer#reset(char[])} with a non-null value will break the link - * with the builder. - * - * @return a tokenizer that is linked to this builder - */ - public StrTokenizer asTokenizer() { - return new StrBuilderTokenizer(); - } - - // ----------------------------------------------------------------------- - /** - * Gets the contents of this builder as a Reader. - *

- * This method allows the contents of the builder to be read using any standard - * method that expects a Reader. - *

- * To use, simply create a {@code StrBuilder}, populate it with data, call - * {@code asReader}, and then read away. - *

- * The internal character array is shared between the builder and the reader. - * This allows you to append to the builder after creating the reader, and the - * changes will be picked up. Note however, that no synchronization occurs, so - * you must perform all operations with the builder and the reader in one - * thread. - *

- * The returned reader supports marking, and ignores the flush method. - * - * @return a reader that reads from this builder - */ - public Reader asReader() { - return new StrBuilderReader(); - } - - // ----------------------------------------------------------------------- - /** - * Gets this builder as a Writer that can be written to. - *

- * This method allows you to populate the contents of the builder using any - * standard method that takes a Writer. - *

- * To use, simply create a {@code StrBuilder}, call {@code asWriter}, and - * populate away. The data is available at any time using the methods of the - * {@code StrBuilder}. - *

- * The internal character array is shared between the builder and the writer. - * This allows you to intermix calls that append to the builder and write using - * the writer and the changes will be occur correctly. Note however, that no - * synchronization occurs, so you must perform all operations with the builder - * and the writer in one thread. - *

- * The returned writer ignores the close and flush methods. - * - * @return a writer that populates this builder - */ - public Writer asWriter() { - return new StrBuilderWriter(); - } - - /** - * Appends current contents of this {@code StrBuilder} to the provided - * {@link Appendable}. - *

- * This method tries to avoid doing any extra copies of contents. - * - * @param appendable the appendable to append data to - * @throws IOException if an I/O error occurs - * - * @since 3.4 - * @see #readFrom(Readable) - */ - public void appendTo(final Appendable appendable) throws IOException { - if (appendable instanceof Writer) { - ((Writer) appendable).write(buffer, 0, size); - } else if (appendable instanceof StringBuilder) { - ((StringBuilder) appendable).append(buffer, 0, size); - } else if (appendable instanceof StringBuffer) { - ((StringBuffer) appendable).append(buffer, 0, size); - } else if (appendable instanceof CharBuffer) { - ((CharBuffer) appendable).put(buffer, 0, size); - } else { - appendable.append(this); - } - } - - /** - * Checks the contents of this builder against another to see if they contain - * the same character content ignoring case. - * - * @param other the object to check, null returns false - * @return true if the builders contain the same characters in the same order - */ - public boolean equalsIgnoreCase(final StrBuilder other) { - if (this == other) { - return true; - } - if (this.size != other.size) { - return false; - } - final char[] thisBuf = this.buffer; - final char[] otherBuf = other.buffer; - for (int i = size - 1; i >= 0; i--) { - final char c1 = thisBuf[i]; - final char c2 = otherBuf[i]; - if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) { - return false; - } - } - return true; - } - - /** - * Checks the contents of this builder against another to see if they contain - * the same character content. - * - * @param other the object to check, null returns false - * @return true if the builders contain the same characters in the same order - */ - public boolean equals(final StrBuilder other) { - if (this == other) { - return true; - } - if (other == null) { - return false; - } - if (this.size != other.size) { - return false; - } - final char[] thisBuf = this.buffer; - final char[] otherBuf = other.buffer; - for (int i = size - 1; i >= 0; i--) { - if (thisBuf[i] != otherBuf[i]) { - return false; - } - } - return true; - } - - /** - * Checks the contents of this builder against another to see if they contain - * the same character content. - * - * @param obj the object to check, null returns false - * @return true if the builders contain the same characters in the same order - */ - @Override - public boolean equals(final Object obj) { - return obj instanceof StrBuilder && equals((StrBuilder) obj); - } - - /** - * Gets a suitable hash code for this builder. - * - * @return a hash code - */ - @Override - public int hashCode() { - final char[] buf = buffer; - int hash = 0; - for (int i = size - 1; i >= 0; i--) { - hash = 31 * hash + buf[i]; - } - return hash; - } - - // ----------------------------------------------------------------------- - /** - * Gets a String version of the string builder, creating a new instance each - * time the method is called. - *

- * Note that unlike StringBuffer, the string version returned is independent of - * the string builder. - * - * @return the builder as a String - */ - @Override - public String toString() { - return new String(buffer, 0, size); - } - - /** - * Gets a StringBuffer version of the string builder, creating a new instance - * each time the method is called. - * - * @return the builder as a StringBuffer - */ - public StringBuffer toStringBuffer() { - return new StringBuffer(size).append(buffer, 0, size); - } - - /** - * Gets a StringBuilder version of the string builder, creating a new instance - * each time the method is called. - * - * @return the builder as a StringBuilder - * @since 3.2 - */ - public StringBuilder toStringBuilder() { - return new StringBuilder(size).append(buffer, 0, size); - } - - /** - * Implement the {@link Builder} interface. - * - * @return the builder as a String - * @since 3.2 - * @see #toString() - */ - @Override - public String build() { - return toString(); - } - - // ----------------------------------------------------------------------- - /** - * Validates parameters defining a range of the builder. - * - * @param startIndex the start index, inclusive, must be valid - * @param endIndex the end index, exclusive, must be valid except that if too - * large it is treated as end of string - * @return the new string - * @throws IndexOutOfBoundsException if the index is invalid - */ - protected int validateRange(final int startIndex, int endIndex) { - if (startIndex < 0) { - throw new StringIndexOutOfBoundsException(startIndex); - } - if (endIndex > size) { - endIndex = size; - } - if (startIndex > endIndex) { - throw new StringIndexOutOfBoundsException("end < start"); - } - return endIndex; - } - - /** - * Validates parameters defining a single index in the builder. - * - * @param index the index, must be valid - * @throws IndexOutOfBoundsException if the index is invalid - */ - protected void validateIndex(final int index) { - if (index < 0 || index > size) { - throw new StringIndexOutOfBoundsException(index); - } - } - - // ----------------------------------------------------------------------- - /** - * Inner class to allow StrBuilder to operate as a tokenizer. - */ - class StrBuilderTokenizer extends StrTokenizer { - - /** - * Default constructor. - */ - StrBuilderTokenizer() { - } - - /** {@inheritDoc} */ - @Override - protected List tokenize(final char[] chars, final int offset, final int count) { - if (chars == null) { - return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size()); - } - return super.tokenize(chars, offset, count); - } - - /** {@inheritDoc} */ - @Override - public String getContent() { - final String str = super.getContent(); - if (str == null) { - return StrBuilder.this.toString(); - } - return str; - } - } - - // ----------------------------------------------------------------------- - /** - * Inner class to allow StrBuilder to operate as a reader. - */ - class StrBuilderReader extends Reader { - /** The current stream position. */ - private int pos; - /** The last mark position. */ - private int mark; - - /** - * Default constructor. - */ - StrBuilderReader() { - } - - /** {@inheritDoc} */ - @Override - public void close() { - // do nothing - } - - /** {@inheritDoc} */ - @Override - public int read() { - if (ready() == false) { - return -1; - } - return StrBuilder.this.charAt(pos++); - } - - /** {@inheritDoc} */ - @Override - public int read(final char[] b, final int off, int len) { - if (off < 0 || len < 0 || off > b.length || (off + len) > b.length || (off + len) < 0) { - throw new IndexOutOfBoundsException(); - } - if (len == 0) { - return 0; - } - if (pos >= StrBuilder.this.size()) { - return -1; - } - if (pos + len > size()) { - len = StrBuilder.this.size() - pos; - } - StrBuilder.this.getChars(pos, pos + len, b, off); - pos += len; - return len; - } - - /** {@inheritDoc} */ - @Override - public long skip(long n) { - if (pos + n > StrBuilder.this.size()) { - n = StrBuilder.this.size() - pos; - } - if (n < 0) { - return 0; - } - pos += n; - return n; - } - - /** {@inheritDoc} */ - @Override - public boolean ready() { - return pos < StrBuilder.this.size(); - } - - /** {@inheritDoc} */ - @Override - public boolean markSupported() { - return true; - } - - /** {@inheritDoc} */ - @Override - public void mark(final int readAheadLimit) { - mark = pos; - } - - /** {@inheritDoc} */ - @Override - public void reset() { - pos = mark; - } - } - - // ----------------------------------------------------------------------- - /** - * Inner class to allow StrBuilder to operate as a writer. - */ - class StrBuilderWriter extends Writer { - - /** - * Default constructor. - */ - StrBuilderWriter() { - } - - /** {@inheritDoc} */ - @Override - public void close() { - // do nothing - } - - /** {@inheritDoc} */ - @Override - public void flush() { - // do nothing - } - - /** {@inheritDoc} */ - @Override - public void write(final int c) { - StrBuilder.this.append((char) c); - } - - /** {@inheritDoc} */ - @Override - public void write(final char[] cbuf) { - StrBuilder.this.append(cbuf); - } - - /** {@inheritDoc} */ - @Override - public void write(final char[] cbuf, final int off, final int len) { - StrBuilder.this.append(cbuf, off, len); - } - - /** {@inheritDoc} */ - @Override - public void write(final String str) { - StrBuilder.this.append(str); - } - - /** {@inheritDoc} */ - @Override - public void write(final String str, final int off, final int len) { - StrBuilder.this.append(str, off, len); - } - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/StrLookup.java b/sources/main/java/org/apache/commons/lang3/text/StrLookup.java deleted file mode 100644 index fa69ba26..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/StrLookup.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text; - -import java.util.Map; - -/** - * Lookup a String key to a String value. - *

- * This class represents the simplest form of a string to string map. It has a - * benefit over a map in that it can create the result on demand based on the - * key. - *

- * This class comes complete with various factory methods. If these do not - * suffice, you can subclass and implement your own matcher. - *

- * For example, it would be possible to implement a lookup that used the key as - * a primary key, and looked up the value on demand from the database. - * - * @param Unused. - * @since 2.2 - * @!deprecated as of 3.6, use commons-text - * StringLookupFactory instead - */ -//@Deprecated -public abstract class StrLookup { - - /** - * Lookup that always returns null. - */ - private static final StrLookup NONE_LOOKUP = new MapStrLookup<>(null); - - /** - * Lookup based on system properties. - */ - private static final StrLookup SYSTEM_PROPERTIES_LOOKUP = new SystemPropertiesStrLookup(); - - // ----------------------------------------------------------------------- - /** - * Returns a lookup which always returns null. - * - * @return a lookup that always returns null, not null - */ - public static StrLookup noneLookup() { - return NONE_LOOKUP; - } - - /** - * Returns a new lookup which uses a copy of the current - * {@link System#getProperties() System properties}. - *

- * If a security manager blocked access to system properties, then null will be - * returned from every lookup. - *

- * If a null key is used, this lookup will throw a NullPointerException. - * - * @return a lookup using system properties, not null - */ - public static StrLookup systemPropertiesLookup() { - return SYSTEM_PROPERTIES_LOOKUP; - } - - /** - * Returns a lookup which looks up values using a map. - *

- * If the map is null, then null will be returned from every lookup. The map - * result object is converted to a string using toString(). - * - * @param the type of the values supported by the lookup - * @param map the map of keys to values, may be null - * @return a lookup using the map, not null - */ - public static StrLookup mapLookup(final Map map) { - return new MapStrLookup<>(map); - } - - // ----------------------------------------------------------------------- - /** - * Constructor. - */ - protected StrLookup() { - } - - /** - * Looks up a String key to a String value. - *

- * The internal implementation may use any mechanism to return the value. The - * simplest implementation is to use a Map. However, virtually any - * implementation is possible. - *

- * For example, it would be possible to implement a lookup that used the key as - * a primary key, and looked up the value on demand from the database Or, a - * numeric based implementation could be created that treats the key as an - * integer, increments the value and return the result as a string - converting - * 1 to 2, 15 to 16 etc. - *

- * The {@link #lookup(String)} method always returns a String, regardless of the - * underlying data, by converting it as necessary. For example: - * - *

-	 * Map<String, Object> map = new HashMap<String, Object>();
-	 * map.put("number", Integer.valueOf(2));
-	 * assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
-	 * 
- * - * @param key the key to be looked up, may be null - * @return the matching value, null if no match - */ - public abstract String lookup(String key); - - // ----------------------------------------------------------------------- - /** - * Lookup implementation that uses a Map. - */ - static class MapStrLookup extends StrLookup { - - /** Map keys are variable names and value. */ - private final Map map; - - /** - * Creates a new instance backed by a Map. - * - * @param map the map of keys to values, may be null - */ - MapStrLookup(final Map map) { - this.map = map; - } - - /** - * Looks up a String key to a String value using the map. - *

- * If the map is null, then null is returned. The map result object is converted - * to a string using toString(). - * - * @param key the key to be looked up, may be null - * @return the matching value, null if no match - */ - @Override - public String lookup(final String key) { - if (map == null) { - return null; - } - final Object obj = map.get(key); - if (obj == null) { - return null; - } - return obj.toString(); - } - } - - // ----------------------------------------------------------------------- - /** - * Lookup implementation based on system properties. - */ - private static class SystemPropertiesStrLookup extends StrLookup { - /** - * {@inheritDoc} This implementation directly accesses system properties. - */ - @Override - public String lookup(final String key) { - if (!key.isEmpty()) { - try { - return System.getProperty(key); - } catch (final SecurityException scex) { - // Squelched. All lookup(String) will return null. - } - } - return null; - } - } -} diff --git a/sources/main/java/org/apache/commons/lang3/text/StrMatcher.java b/sources/main/java/org/apache/commons/lang3/text/StrMatcher.java deleted file mode 100644 index 80661d53..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/StrMatcher.java +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text; - -import java.util.Arrays; - -import org.apache.commons.lang3.ArraySorter; -import org.apache.commons.lang3.StringUtils; - -/** - * A matcher class that can be queried to determine if a character array portion - * matches. - *

- * This class comes complete with various factory methods. If these do not - * suffice, you can subclass and implement your own matcher. - * - * @since 2.2 - * @!deprecated as of 3.6, use commons-text - * StringMatcherFactory instead - */ -//@Deprecated -public abstract class StrMatcher { - - /** - * Matches the comma character. - */ - private static final StrMatcher COMMA_MATCHER = new CharMatcher(','); - /** - * Matches the tab character. - */ - private static final StrMatcher TAB_MATCHER = new CharMatcher('\t'); - /** - * Matches the space character. - */ - private static final StrMatcher SPACE_MATCHER = new CharMatcher(' '); - /** - * Matches the same characters as StringTokenizer, namely space, tab, newline, - * formfeed. - */ - private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray()); - /** - * Matches the String trim() whitespace characters. - */ - private static final StrMatcher TRIM_MATCHER = new TrimMatcher(); - /** - * Matches the double quote character. - */ - private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\''); - /** - * Matches the double quote character. - */ - private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"'); - /** - * Matches the single or double quote character. - */ - private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray()); - /** - * Matches no characters. - */ - private static final StrMatcher NONE_MATCHER = new NoMatcher(); - - // ----------------------------------------------------------------------- - - /** - * Returns a matcher which matches the comma character. - * - * @return a matcher for a comma - */ - public static StrMatcher commaMatcher() { - return COMMA_MATCHER; - } - - /** - * Returns a matcher which matches the tab character. - * - * @return a matcher for a tab - */ - public static StrMatcher tabMatcher() { - return TAB_MATCHER; - } - - /** - * Returns a matcher which matches the space character. - * - * @return a matcher for a space - */ - public static StrMatcher spaceMatcher() { - return SPACE_MATCHER; - } - - /** - * Matches the same characters as StringTokenizer, namely space, tab, newline - * and formfeed. - * - * @return the split matcher - */ - public static StrMatcher splitMatcher() { - return SPLIT_MATCHER; - } - - /** - * Matches the String trim() whitespace characters. - * - * @return the trim matcher - */ - public static StrMatcher trimMatcher() { - return TRIM_MATCHER; - } - - /** - * Returns a matcher which matches the single quote character. - * - * @return a matcher for a single quote - */ - public static StrMatcher singleQuoteMatcher() { - return SINGLE_QUOTE_MATCHER; - } - - /** - * Returns a matcher which matches the double quote character. - * - * @return a matcher for a double quote - */ - public static StrMatcher doubleQuoteMatcher() { - return DOUBLE_QUOTE_MATCHER; - } - - /** - * Returns a matcher which matches the single or double quote character. - * - * @return a matcher for a single or double quote - */ - public static StrMatcher quoteMatcher() { - return QUOTE_MATCHER; - } - - /** - * Matches no characters. - * - * @return a matcher that matches nothing - */ - public static StrMatcher noneMatcher() { - return NONE_MATCHER; - } - - /** - * Constructor that creates a matcher from a character. - * - * @param ch the character to match, must not be null - * @return a new Matcher for the given char - */ - public static StrMatcher charMatcher(final char ch) { - return new CharMatcher(ch); - } - - /** - * Constructor that creates a matcher from a set of characters. - * - * @param chars the characters to match, null or empty matches nothing - * @return a new matcher for the given char[] - */ - public static StrMatcher charSetMatcher(final char... chars) { - if (chars == null || chars.length == 0) { - return NONE_MATCHER; - } - if (chars.length == 1) { - return new CharMatcher(chars[0]); - } - return new CharSetMatcher(chars); - } - - /** - * Constructor that creates a matcher from a string representing a set of - * characters. - * - * @param chars the characters to match, null or empty matches nothing - * @return a new Matcher for the given characters - */ - public static StrMatcher charSetMatcher(final String chars) { - if (StringUtils.isEmpty(chars)) { - return NONE_MATCHER; - } - if (chars.length() == 1) { - return new CharMatcher(chars.charAt(0)); - } - return new CharSetMatcher(chars.toCharArray()); - } - - /** - * Constructor that creates a matcher from a string. - * - * @param str the string to match, null or empty matches nothing - * @return a new Matcher for the given String - */ - public static StrMatcher stringMatcher(final String str) { - if (StringUtils.isEmpty(str)) { - return NONE_MATCHER; - } - return new StringMatcher(str); - } - - // ----------------------------------------------------------------------- - /** - * Constructor. - */ - protected StrMatcher() { - } - - /** - * Returns the number of matching characters, zero for no match. - *

- * This method is called to check for a match. The parameter {@code pos} - * represents the current position to be checked in the string {@code buffer} (a - * character array which must not be changed). The API guarantees that - * {@code pos} is a valid index for {@code buffer}. - *

- * The character array may be larger than the active area to be matched. Only - * values in the buffer between the specified indices may be accessed. - *

- * The matching code may check one character or many. It may check characters - * preceding {@code pos} as well as those after, so long as no checks exceed the - * bounds specified. - *

- * It must return zero for no match, or a positive number if a match was found. - * The number indicates the number of characters that matched. - * - * @param buffer the text content to match against, do not change - * @param pos the starting position for the match, valid for buffer - * @param bufferStart the first active index in the buffer, valid for buffer - * @param bufferEnd the end index (exclusive) of the active buffer, valid for - * buffer - * @return the number of matching characters, zero for no match - */ - public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd); - - /** - * Returns the number of matching characters, zero for no match. - *

- * This method is called to check for a match. The parameter {@code pos} - * represents the current position to be checked in the string {@code buffer} (a - * character array which must not be changed). The API guarantees that - * {@code pos} is a valid index for {@code buffer}. - *

- * The matching code may check one character or many. It may check characters - * preceding {@code pos} as well as those after. - *

- * It must return zero for no match, or a positive number if a match was found. - * The number indicates the number of characters that matched. - * - * @param buffer the text content to match against, do not change - * @param pos the starting position for the match, valid for buffer - * @return the number of matching characters, zero for no match - * @since 2.4 - */ - public int isMatch(final char[] buffer, final int pos) { - return isMatch(buffer, pos, 0, buffer.length); - } - - // ----------------------------------------------------------------------- - /** - * Class used to define a set of characters for matching purposes. - */ - static final class CharSetMatcher extends StrMatcher { - /** The set of characters to match. */ - private final char[] chars; - - /** - * Constructor that creates a matcher from a character array. - * - * @param chars the characters to match, must not be null - */ - CharSetMatcher(final char[] chars) { - this.chars = ArraySorter.sort(chars.clone()); - } - - /** - * Returns whether or not the given character matches. - * - * @param buffer the text content to match against, do not change - * @param pos the starting position for the match, valid for buffer - * @param bufferStart the first active index in the buffer, valid for buffer - * @param bufferEnd the end index of the active buffer, valid for buffer - * @return the number of matching characters, zero for no match - */ - @Override - public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { - return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0; - } - } - - // ----------------------------------------------------------------------- - /** - * Class used to define a character for matching purposes. - */ - static final class CharMatcher extends StrMatcher { - /** The character to match. */ - private final char ch; - - /** - * Constructor that creates a matcher that matches a single character. - * - * @param ch the character to match - */ - CharMatcher(final char ch) { - this.ch = ch; - } - - /** - * Returns whether or not the given character matches. - * - * @param buffer the text content to match against, do not change - * @param pos the starting position for the match, valid for buffer - * @param bufferStart the first active index in the buffer, valid for buffer - * @param bufferEnd the end index of the active buffer, valid for buffer - * @return the number of matching characters, zero for no match - */ - @Override - public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { - return ch == buffer[pos] ? 1 : 0; - } - } - - // ----------------------------------------------------------------------- - /** - * Class used to define a set of characters for matching purposes. - */ - static final class StringMatcher extends StrMatcher { - /** The string to match, as a character array. */ - private final char[] chars; - - /** - * Constructor that creates a matcher from a String. - * - * @param str the string to match, must not be null - */ - StringMatcher(final String str) { - chars = str.toCharArray(); - } - - /** - * Returns whether or not the given text matches the stored string. - * - * @param buffer the text content to match against, do not change - * @param pos the starting position for the match, valid for buffer - * @param bufferStart the first active index in the buffer, valid for buffer - * @param bufferEnd the end index of the active buffer, valid for buffer - * @return the number of matching characters, zero for no match - */ - @Override - public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) { - final int len = chars.length; - if (pos + len > bufferEnd) { - return 0; - } - for (int i = 0; i < chars.length; i++, pos++) { - if (chars[i] != buffer[pos]) { - return 0; - } - } - return len; - } - - @Override - public String toString() { - return super.toString() + ' ' + Arrays.toString(chars); - } - - } - - // ----------------------------------------------------------------------- - /** - * Class used to match no characters. - */ - static final class NoMatcher extends StrMatcher { - - /** - * Constructs a new instance of {@code NoMatcher}. - */ - NoMatcher() { - } - - /** - * Always returns {@code false}. - * - * @param buffer the text content to match against, do not change - * @param pos the starting position for the match, valid for buffer - * @param bufferStart the first active index in the buffer, valid for buffer - * @param bufferEnd the end index of the active buffer, valid for buffer - * @return the number of matching characters, zero for no match - */ - @Override - public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { - return 0; - } - } - - // ----------------------------------------------------------------------- - /** - * Class used to match whitespace as per trim(). - */ - static final class TrimMatcher extends StrMatcher { - - /** - * Constructs a new instance of {@code TrimMatcher}. - */ - TrimMatcher() { - } - - /** - * Returns whether or not the given character matches. - * - * @param buffer the text content to match against, do not change - * @param pos the starting position for the match, valid for buffer - * @param bufferStart the first active index in the buffer, valid for buffer - * @param bufferEnd the end index of the active buffer, valid for buffer - * @return the number of matching characters, zero for no match - */ - @Override - public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { - return buffer[pos] <= 32 ? 1 : 0; - } - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/StrSubstitutor.java b/sources/main/java/org/apache/commons/lang3/text/StrSubstitutor.java deleted file mode 100644 index eb8a943b..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/StrSubstitutor.java +++ /dev/null @@ -1,1262 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text; - -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import org.apache.commons.lang3.StringUtils; - -/** - * Substitutes variables within a string by values. - *

- * This class takes a piece of text and substitutes all the variables within it. - * The default definition of a variable is {@code ${variableName}}. The prefix - * and suffix can be changed via constructors and set methods. - *

- * Variable values are typically resolved from a map, but could also be resolved - * from system properties, or by supplying a custom variable resolver. - *

- * The simplest example is to use this class to replace Java System properties. - * For example: - * - *

- * StrSubstitutor
- * 		.replaceSystemProperties("You are running with java.version = ${java.version} and os.name = ${os.name}.");
- * 
- *

- * Typical usage of this class follows the following pattern: First an instance - * is created and initialized with the map that contains the values for the - * available variables. If a prefix and/or suffix for variables should be used - * other than the default ones, the appropriate settings can be performed. After - * that the {@code replace()} method can be called passing in the source text - * for interpolation. In the returned text all variable references (as long as - * their values are known) will be resolved. The following example demonstrates - * this: - * - *

- * Map valuesMap = HashMap();
- * valuesMap.put("animal", "quick brown fox");
- * valuesMap.put("target", "lazy dog");
- * String templateString = "The ${animal} jumps over the ${target}.";
- * StrSubstitutor sub = new StrSubstitutor(valuesMap);
- * String resolvedString = sub.replace(templateString);
- * 
- * - * yielding: - * - *
- *      The quick brown fox jumps over the lazy dog.
- * 
- *

- * Also, this class allows to set a default value for unresolved variables. The - * default value for a variable can be appended to the variable name after the - * variable default value delimiter. The default value of the variable default - * value delimiter is ':-', as in bash and other *nix shells, as those are - * arguably where the default ${} delimiter set originated. The variable default - * value delimiter can be manually set by calling - * {@link #setValueDelimiterMatcher(StrMatcher)}, - * {@link #setValueDelimiter(char)} or {@link #setValueDelimiter(String)}. The - * following shows an example with variable default value settings: - * - *

- * Map valuesMap = HashMap();
- * valuesMap.put("animal", "quick brown fox");
- * valuesMap.put("target", "lazy dog");
- * String templateString = "The ${animal} jumps over the ${target}. ${undefined.number:-1234567890}.";
- * StrSubstitutor sub = new StrSubstitutor(valuesMap);
- * String resolvedString = sub.replace(templateString);
- * 
- * - * yielding: - * - *
- *      The quick brown fox jumps over the lazy dog. 1234567890.
- * 
- *

- * In addition to this usage pattern there are some static convenience methods - * that cover the most common use cases. These methods can be used without the - * need of manually creating an instance. However if multiple replace operations - * are to be performed, creating and reusing an instance of this class will be - * more efficient. - *

- * Variable replacement works in a recursive way. Thus, if a variable value - * contains a variable then that variable will also be replaced. Cyclic - * replacements are detected and will cause an exception to be thrown. - *

- * Sometimes the interpolation's result must contain a variable prefix. As an - * example take the following source text: - * - *

- *   The variable ${${name}} must be used.
- * 
- * - * Here only the variable's name referred to in the text should be replaced - * resulting in the text (assuming that the value of the {@code name} variable - * is {@code x}): - * - *
- *   The variable ${x} must be used.
- * 
- * - * To achieve this effect there are two possibilities: Either set a different - * prefix and suffix for variables which do not conflict with the result text - * you want to produce. The other possibility is to use the escape character, by - * default '$'. If this character is placed before a variable reference, this - * reference is ignored and won't be replaced. For example: - * - *
- *   The variable $${${name}} must be used.
- * 
- *

- * In some complex scenarios you might even want to perform substitution in the - * names of variables, for instance - * - *

- * ${jre-${java.specification.version}}
- * 
- * - * {@code StrSubstitutor} supports this recursive substitution in variable - * names, but it has to be enabled explicitly by setting the - * {@link #setEnableSubstitutionInVariables(boolean) - * enableSubstitutionInVariables} property to true. - *

- * This class is not thread safe. - *

- * - * @since 2.2 - * @!deprecated as of 3.6, use commons-text - * StringSubstitutor instead - */ -//@Deprecated -public class StrSubstitutor { - - /** - * Constant for the default escape character. - */ - public static final char DEFAULT_ESCAPE = '$'; - /** - * Constant for the default variable prefix. - */ - public static final StrMatcher DEFAULT_PREFIX = StrMatcher.stringMatcher("${"); - /** - * Constant for the default variable suffix. - */ - public static final StrMatcher DEFAULT_SUFFIX = StrMatcher.stringMatcher("}"); - /** - * Constant for the default value delimiter of a variable. - * - * @since 3.2 - */ - public static final StrMatcher DEFAULT_VALUE_DELIMITER = StrMatcher.stringMatcher(":-"); - - /** - * Stores the escape character. - */ - private char escapeChar; - /** - * Stores the variable prefix. - */ - private StrMatcher prefixMatcher; - /** - * Stores the variable suffix. - */ - private StrMatcher suffixMatcher; - /** - * Stores the default variable value delimiter - */ - private StrMatcher valueDelimiterMatcher; - /** - * Variable resolution is delegated to an implementor of VariableResolver. - */ - private StrLookup variableResolver; - /** - * The flag whether substitution in variable names is enabled. - */ - private boolean enableSubstitutionInVariables; - /** - * Whether escapes should be preserved. Default is false; - */ - private boolean preserveEscapes; - - // ----------------------------------------------------------------------- - /** - * Replaces all the occurrences of variables in the given source object with - * their matching values from the map. - * - * @param the type of the values in the map - * @param source the source text containing the variables to substitute, null - * returns null - * @param valueMap the map with the values, may be null - * @return the result of the replace operation - */ - public static String replace(final Object source, final Map valueMap) { - return new StrSubstitutor(valueMap).replace(source); - } - - /** - * Replaces all the occurrences of variables in the given source object with - * their matching values from the map. This method allows to specify a custom - * variable prefix and suffix - * - * @param the type of the values in the map - * @param source the source text containing the variables to substitute, null - * returns null - * @param valueMap the map with the values, may be null - * @param prefix the prefix of variables, not null - * @param suffix the suffix of variables, not null - * @return the result of the replace operation - * @throws IllegalArgumentException if the prefix or suffix is null - */ - public static String replace(final Object source, final Map valueMap, final String prefix, - final String suffix) { - return new StrSubstitutor(valueMap, prefix, suffix).replace(source); - } - - /** - * Replaces all the occurrences of variables in the given source object with - * their matching values from the properties. - * - * @param source the source text containing the variables to - * substitute, null returns null - * @param valueProperties the properties with values, may be null - * @return the result of the replace operation - */ - public static String replace(final Object source, final Properties valueProperties) { - if (valueProperties == null) { - return source.toString(); - } - final Map valueMap = new HashMap<>(); - final Enumeration propNames = valueProperties.propertyNames(); - while (propNames.hasMoreElements()) { - final String propName = (String) propNames.nextElement(); - final String propValue = valueProperties.getProperty(propName); - valueMap.put(propName, propValue); - } - return replace(source, valueMap); - } - - /** - * Replaces all the occurrences of variables in the given source object with - * their matching values from the system properties. - * - * @param source the source text containing the variables to substitute, null - * returns null - * @return the result of the replace operation - */ - public static String replaceSystemProperties(final Object source) { - return new StrSubstitutor(StrLookup.systemPropertiesLookup()).replace(source); - } - - // ----------------------------------------------------------------------- - /** - * Creates a new instance with defaults for variable prefix and suffix and the - * escaping character. - */ - public StrSubstitutor() { - this(null, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); - } - - /** - * Creates a new instance and initializes it. Uses defaults for variable prefix - * and suffix and the escaping character. - * - * @param the type of the values in the map - * @param valueMap the map with the variables' values, may be null - */ - public StrSubstitutor(final Map valueMap) { - this(StrLookup.mapLookup(valueMap), DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); - } - - /** - * Creates a new instance and initializes it. Uses a default escaping character. - * - * @param the type of the values in the map - * @param valueMap the map with the variables' values, may be null - * @param prefix the prefix for variables, not null - * @param suffix the suffix for variables, not null - * @throws IllegalArgumentException if the prefix or suffix is null - */ - public StrSubstitutor(final Map valueMap, final String prefix, final String suffix) { - this(StrLookup.mapLookup(valueMap), prefix, suffix, DEFAULT_ESCAPE); - } - - /** - * Creates a new instance and initializes it. - * - * @param the type of the values in the map - * @param valueMap the map with the variables' values, may be null - * @param prefix the prefix for variables, not null - * @param suffix the suffix for variables, not null - * @param escape the escape character - * @throws IllegalArgumentException if the prefix or suffix is null - */ - public StrSubstitutor(final Map valueMap, final String prefix, final String suffix, - final char escape) { - this(StrLookup.mapLookup(valueMap), prefix, suffix, escape); - } - - /** - * Creates a new instance and initializes it. - * - * @param the type of the values in the map - * @param valueMap the map with the variables' values, may be null - * @param prefix the prefix for variables, not null - * @param suffix the suffix for variables, not null - * @param escape the escape character - * @param valueDelimiter the variable default value delimiter, may be null - * @throws IllegalArgumentException if the prefix or suffix is null - * @since 3.2 - */ - public StrSubstitutor(final Map valueMap, final String prefix, final String suffix, - final char escape, final String valueDelimiter) { - this(StrLookup.mapLookup(valueMap), prefix, suffix, escape, valueDelimiter); - } - - /** - * Creates a new instance and initializes it. - * - * @param variableResolver the variable resolver, may be null - */ - public StrSubstitutor(final StrLookup variableResolver) { - this(variableResolver, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); - } - - /** - * Creates a new instance and initializes it. - * - * @param variableResolver the variable resolver, may be null - * @param prefix the prefix for variables, not null - * @param suffix the suffix for variables, not null - * @param escape the escape character - * @throws IllegalArgumentException if the prefix or suffix is null - */ - public StrSubstitutor(final StrLookup variableResolver, final String prefix, final String suffix, - final char escape) { - this.setVariableResolver(variableResolver); - this.setVariablePrefix(prefix); - this.setVariableSuffix(suffix); - this.setEscapeChar(escape); - this.setValueDelimiterMatcher(DEFAULT_VALUE_DELIMITER); - } - - /** - * Creates a new instance and initializes it. - * - * @param variableResolver the variable resolver, may be null - * @param prefix the prefix for variables, not null - * @param suffix the suffix for variables, not null - * @param escape the escape character - * @param valueDelimiter the variable default value delimiter string, may be - * null - * @throws IllegalArgumentException if the prefix or suffix is null - * @since 3.2 - */ - public StrSubstitutor(final StrLookup variableResolver, final String prefix, final String suffix, - final char escape, final String valueDelimiter) { - this.setVariableResolver(variableResolver); - this.setVariablePrefix(prefix); - this.setVariableSuffix(suffix); - this.setEscapeChar(escape); - this.setValueDelimiter(valueDelimiter); - } - - /** - * Creates a new instance and initializes it. - * - * @param variableResolver the variable resolver, may be null - * @param prefixMatcher the prefix for variables, not null - * @param suffixMatcher the suffix for variables, not null - * @param escape the escape character - * @throws IllegalArgumentException if the prefix or suffix is null - */ - public StrSubstitutor(final StrLookup variableResolver, final StrMatcher prefixMatcher, - final StrMatcher suffixMatcher, final char escape) { - this(variableResolver, prefixMatcher, suffixMatcher, escape, DEFAULT_VALUE_DELIMITER); - } - - /** - * Creates a new instance and initializes it. - * - * @param variableResolver the variable resolver, may be null - * @param prefixMatcher the prefix for variables, not null - * @param suffixMatcher the suffix for variables, not null - * @param escape the escape character - * @param valueDelimiterMatcher the variable default value delimiter matcher, - * may be null - * @throws IllegalArgumentException if the prefix or suffix is null - * @since 3.2 - */ - public StrSubstitutor(final StrLookup variableResolver, final StrMatcher prefixMatcher, - final StrMatcher suffixMatcher, final char escape, final StrMatcher valueDelimiterMatcher) { - this.setVariableResolver(variableResolver); - this.setVariablePrefixMatcher(prefixMatcher); - this.setVariableSuffixMatcher(suffixMatcher); - this.setEscapeChar(escape); - this.setValueDelimiterMatcher(valueDelimiterMatcher); - } - - // ----------------------------------------------------------------------- - /** - * Replaces all the occurrences of variables with their matching values from the - * resolver using the given source string as a template. - * - * @param source the string to replace in, null returns null - * @return the result of the replace operation - */ - public String replace(final String source) { - if (source == null) { - return null; - } - final StrBuilder buf = new StrBuilder(source); - if (substitute(buf, 0, source.length()) == false) { - return source; - } - return buf.toString(); - } - - /** - * Replaces all the occurrences of variables with their matching values from the - * resolver using the given source string as a template. - *

- * Only the specified portion of the string will be processed. The rest of the - * string is not processed, and is not returned. - * - * @param source the string to replace in, null returns null - * @param offset the start offset within the array, must be valid - * @param length the length within the array to be processed, must be valid - * @return the result of the replace operation - */ - public String replace(final String source, final int offset, final int length) { - if (source == null) { - return null; - } - final StrBuilder buf = new StrBuilder(length).append(source, offset, length); - if (substitute(buf, 0, length) == false) { - return source.substring(offset, offset + length); - } - return buf.toString(); - } - - // ----------------------------------------------------------------------- - /** - * Replaces all the occurrences of variables with their matching values from the - * resolver using the given source array as a template. The array is not altered - * by this method. - * - * @param source the character array to replace in, not altered, null returns - * null - * @return the result of the replace operation - */ - public String replace(final char[] source) { - if (source == null) { - return null; - } - final StrBuilder buf = new StrBuilder(source.length).append(source); - substitute(buf, 0, source.length); - return buf.toString(); - } - - /** - * Replaces all the occurrences of variables with their matching values from the - * resolver using the given source array as a template. The array is not altered - * by this method. - *

- * Only the specified portion of the array will be processed. The rest of the - * array is not processed, and is not returned. - * - * @param source the character array to replace in, not altered, null returns - * null - * @param offset the start offset within the array, must be valid - * @param length the length within the array to be processed, must be valid - * @return the result of the replace operation - */ - public String replace(final char[] source, final int offset, final int length) { - if (source == null) { - return null; - } - final StrBuilder buf = new StrBuilder(length).append(source, offset, length); - substitute(buf, 0, length); - return buf.toString(); - } - - // ----------------------------------------------------------------------- - /** - * Replaces all the occurrences of variables with their matching values from the - * resolver using the given source buffer as a template. The buffer is not - * altered by this method. - * - * @param source the buffer to use as a template, not changed, null returns null - * @return the result of the replace operation - */ - public String replace(final StringBuffer source) { - if (source == null) { - return null; - } - final StrBuilder buf = new StrBuilder(source.length()).append(source); - substitute(buf, 0, buf.length()); - return buf.toString(); - } - - /** - * Replaces all the occurrences of variables with their matching values from the - * resolver using the given source buffer as a template. The buffer is not - * altered by this method. - *

- * Only the specified portion of the buffer will be processed. The rest of the - * buffer is not processed, and is not returned. - * - * @param source the buffer to use as a template, not changed, null returns null - * @param offset the start offset within the array, must be valid - * @param length the length within the array to be processed, must be valid - * @return the result of the replace operation - */ - public String replace(final StringBuffer source, final int offset, final int length) { - if (source == null) { - return null; - } - final StrBuilder buf = new StrBuilder(length).append(source, offset, length); - substitute(buf, 0, length); - return buf.toString(); - } - - /** - * Replaces all the occurrences of variables with their matching values from the - * resolver using the given source as a template. The source is not altered by - * this method. - * - * @param source the buffer to use as a template, not changed, null returns null - * @return the result of the replace operation - * @since 3.2 - */ - public String replace(final CharSequence source) { - if (source == null) { - return null; - } - return replace(source, 0, source.length()); - } - - /** - * Replaces all the occurrences of variables with their matching values from the - * resolver using the given source as a template. The source is not altered by - * this method. - *

- * Only the specified portion of the buffer will be processed. The rest of the - * buffer is not processed, and is not returned. - * - * @param source the buffer to use as a template, not changed, null returns null - * @param offset the start offset within the array, must be valid - * @param length the length within the array to be processed, must be valid - * @return the result of the replace operation - * @since 3.2 - */ - public String replace(final CharSequence source, final int offset, final int length) { - if (source == null) { - return null; - } - final StrBuilder buf = new StrBuilder(length).append(source, offset, length); - substitute(buf, 0, length); - return buf.toString(); - } - - // ----------------------------------------------------------------------- - /** - * Replaces all the occurrences of variables with their matching values from the - * resolver using the given source builder as a template. The builder is not - * altered by this method. - * - * @param source the builder to use as a template, not changed, null returns - * null - * @return the result of the replace operation - */ - public String replace(final StrBuilder source) { - if (source == null) { - return null; - } - final StrBuilder buf = new StrBuilder(source.length()).append(source); - substitute(buf, 0, buf.length()); - return buf.toString(); - } - - /** - * Replaces all the occurrences of variables with their matching values from the - * resolver using the given source builder as a template. The builder is not - * altered by this method. - *

- * Only the specified portion of the builder will be processed. The rest of the - * builder is not processed, and is not returned. - * - * @param source the builder to use as a template, not changed, null returns - * null - * @param offset the start offset within the array, must be valid - * @param length the length within the array to be processed, must be valid - * @return the result of the replace operation - */ - public String replace(final StrBuilder source, final int offset, final int length) { - if (source == null) { - return null; - } - final StrBuilder buf = new StrBuilder(length).append(source, offset, length); - substitute(buf, 0, length); - return buf.toString(); - } - - // ----------------------------------------------------------------------- - /** - * Replaces all the occurrences of variables in the given source object with - * their matching values from the resolver. The input source object is converted - * to a string using {@code toString} and is not altered. - * - * @param source the source to replace in, null returns null - * @return the result of the replace operation - */ - public String replace(final Object source) { - if (source == null) { - return null; - } - final StrBuilder buf = new StrBuilder().append(source); - substitute(buf, 0, buf.length()); - return buf.toString(); - } - - // ----------------------------------------------------------------------- - /** - * Replaces all the occurrences of variables within the given source buffer with - * their matching values from the resolver. The buffer is updated with the - * result. - * - * @param source the buffer to replace in, updated, null returns zero - * @return true if altered - */ - public boolean replaceIn(final StringBuffer source) { - if (source == null) { - return false; - } - return replaceIn(source, 0, source.length()); - } - - /** - * Replaces all the occurrences of variables within the given source buffer with - * their matching values from the resolver. The buffer is updated with the - * result. - *

- * Only the specified portion of the buffer will be processed. The rest of the - * buffer is not processed, but it is not deleted. - * - * @param source the buffer to replace in, updated, null returns zero - * @param offset the start offset within the array, must be valid - * @param length the length within the buffer to be processed, must be valid - * @return true if altered - */ - public boolean replaceIn(final StringBuffer source, final int offset, final int length) { - if (source == null) { - return false; - } - final StrBuilder buf = new StrBuilder(length).append(source, offset, length); - if (substitute(buf, 0, length) == false) { - return false; - } - source.replace(offset, offset + length, buf.toString()); - return true; - } - - // ----------------------------------------------------------------------- - /** - * Replaces all the occurrences of variables within the given source buffer with - * their matching values from the resolver. The buffer is updated with the - * result. - * - * @param source the buffer to replace in, updated, null returns zero - * @return true if altered - * @since 3.2 - */ - public boolean replaceIn(final StringBuilder source) { - if (source == null) { - return false; - } - return replaceIn(source, 0, source.length()); - } - - /** - * Replaces all the occurrences of variables within the given source builder - * with their matching values from the resolver. The builder is updated with the - * result. - *

- * Only the specified portion of the buffer will be processed. The rest of the - * buffer is not processed, but it is not deleted. - * - * @param source the buffer to replace in, updated, null returns zero - * @param offset the start offset within the array, must be valid - * @param length the length within the buffer to be processed, must be valid - * @return true if altered - * @since 3.2 - */ - public boolean replaceIn(final StringBuilder source, final int offset, final int length) { - if (source == null) { - return false; - } - final StrBuilder buf = new StrBuilder(length).append(source, offset, length); - if (substitute(buf, 0, length) == false) { - return false; - } - source.replace(offset, offset + length, buf.toString()); - return true; - } - - // ----------------------------------------------------------------------- - /** - * Replaces all the occurrences of variables within the given source builder - * with their matching values from the resolver. - * - * @param source the builder to replace in, updated, null returns zero - * @return true if altered - */ - public boolean replaceIn(final StrBuilder source) { - if (source == null) { - return false; - } - return substitute(source, 0, source.length()); - } - - /** - * Replaces all the occurrences of variables within the given source builder - * with their matching values from the resolver. - *

- * Only the specified portion of the builder will be processed. The rest of the - * builder is not processed, but it is not deleted. - * - * @param source the builder to replace in, null returns zero - * @param offset the start offset within the array, must be valid - * @param length the length within the builder to be processed, must be valid - * @return true if altered - */ - public boolean replaceIn(final StrBuilder source, final int offset, final int length) { - if (source == null) { - return false; - } - return substitute(source, offset, length); - } - - // ----------------------------------------------------------------------- - /** - * Internal method that substitutes the variables. - *

- * Most users of this class do not need to call this method. This method will be - * called automatically by another (public) method. - *

- * Writers of subclasses can override this method if they need access to the - * substitution process at the start or end. - * - * @param buf the string builder to substitute into, not null - * @param offset the start offset within the builder, must be valid - * @param length the length within the builder to be processed, must be valid - * @return true if altered - */ - protected boolean substitute(final StrBuilder buf, final int offset, final int length) { - return substitute(buf, offset, length, null) > 0; - } - - /** - * Recursive handler for multiple levels of interpolation. This is the main - * interpolation method, which resolves the values of all variable references - * contained in the passed in text. - * - * @param buf the string builder to substitute into, not null - * @param offset the start offset within the builder, must be valid - * @param length the length within the builder to be processed, must be - * valid - * @param priorVariables the stack keeping track of the replaced variables, may - * be null - * @return the length change that occurs, unless priorVariables is null when the - * int represents a boolean flag as to whether any change occurred. - */ - private int substitute(final StrBuilder buf, final int offset, final int length, List priorVariables) { - final StrMatcher pfxMatcher = getVariablePrefixMatcher(); - final StrMatcher suffMatcher = getVariableSuffixMatcher(); - final char escape = getEscapeChar(); - final StrMatcher valueDelimMatcher = getValueDelimiterMatcher(); - final boolean substitutionInVariablesEnabled = isEnableSubstitutionInVariables(); - - final boolean top = priorVariables == null; - boolean altered = false; - int lengthChange = 0; - char[] chars = buf.buffer; - int bufEnd = offset + length; - int pos = offset; - while (pos < bufEnd) { - final int startMatchLen = pfxMatcher.isMatch(chars, pos, offset, bufEnd); - if (startMatchLen == 0) { - pos++; - } else // found variable start marker - if (pos > offset && chars[pos - 1] == escape) { - // escaped - if (preserveEscapes) { - pos++; - continue; - } - buf.deleteCharAt(pos - 1); - chars = buf.buffer; // in case buffer was altered - lengthChange--; - altered = true; - bufEnd--; - } else { - // find suffix - final int startPos = pos; - pos += startMatchLen; - int endMatchLen = 0; - int nestedVarCount = 0; - while (pos < bufEnd) { - if (substitutionInVariablesEnabled - && (endMatchLen = pfxMatcher.isMatch(chars, pos, offset, bufEnd)) != 0) { - // found a nested variable start - nestedVarCount++; - pos += endMatchLen; - continue; - } - - endMatchLen = suffMatcher.isMatch(chars, pos, offset, bufEnd); - if (endMatchLen == 0) { - pos++; - } else { - // found variable end marker - if (nestedVarCount == 0) { - String varNameExpr = new String(chars, startPos + startMatchLen, - pos - startPos - startMatchLen); - if (substitutionInVariablesEnabled) { - final StrBuilder bufName = new StrBuilder(varNameExpr); - substitute(bufName, 0, bufName.length()); - varNameExpr = bufName.toString(); - } - pos += endMatchLen; - final int endPos = pos; - - String varName = varNameExpr; - String varDefaultValue = null; - - if (valueDelimMatcher != null) { - final char[] varNameExprChars = varNameExpr.toCharArray(); - int valueDelimiterMatchLen = 0; - for (int i = 0; i < varNameExprChars.length; i++) { - // if there's any nested variable when nested variable substitution disabled, - // then stop resolving name and default value. - if (!substitutionInVariablesEnabled && pfxMatcher.isMatch(varNameExprChars, i, i, - varNameExprChars.length) != 0) { - break; - } - if ((valueDelimiterMatchLen = valueDelimMatcher.isMatch(varNameExprChars, - i)) != 0) { - varName = varNameExpr.substring(0, i); - varDefaultValue = varNameExpr.substring(i + valueDelimiterMatchLen); - break; - } - } - } - - // on the first call initialize priorVariables - if (priorVariables == null) { - priorVariables = new ArrayList<>(); - priorVariables.add(new String(chars, offset, length)); - } - - // handle cyclic substitution - checkCyclicSubstitution(varName, priorVariables); - priorVariables.add(varName); - - // resolve the variable - String varValue = resolveVariable(varName, buf, startPos, endPos); - if (varValue == null) { - varValue = varDefaultValue; - } - if (varValue != null) { - // recursive replace - final int varLen = varValue.length(); - buf.replace(startPos, endPos, varValue); - altered = true; - int change = substitute(buf, startPos, varLen, priorVariables); - change = change + varLen - (endPos - startPos); - pos += change; - bufEnd += change; - lengthChange += change; - chars = buf.buffer; // in case buffer was - // altered - } - - // remove variable from the cyclic stack - priorVariables.remove(priorVariables.size() - 1); - break; - } - nestedVarCount--; - pos += endMatchLen; - } - } - } - } - if (top) { - return altered ? 1 : 0; - } - return lengthChange; - } - - /** - * Checks if the specified variable is already in the stack (list) of variables. - * - * @param varName the variable name to check - * @param priorVariables the list of prior variables - */ - private void checkCyclicSubstitution(final String varName, final List priorVariables) { - if (priorVariables.contains(varName) == false) { - return; - } - final StrBuilder buf = new StrBuilder(256); - buf.append("Infinite loop in property interpolation of "); - buf.append(priorVariables.remove(0)); - buf.append(": "); - buf.appendWithSeparators(priorVariables, "->"); - throw new IllegalStateException(buf.toString()); - } - - /** - * Internal method that resolves the value of a variable. - *

- * Most users of this class do not need to call this method. This method is - * called automatically by the substitution process. - *

- * Writers of subclasses can override this method if they need to alter how each - * substitution occurs. The method is passed the variable's name and must return - * the corresponding value. This implementation uses the - * {@link #getVariableResolver()} with the variable's name as the key. - * - * @param variableName the name of the variable, not null - * @param buf the buffer where the substitution is occurring, not null - * @param startPos the start position of the variable including the prefix, - * valid - * @param endPos the end position of the variable including the suffix, - * valid - * @return the variable's value or null if the variable is unknown - */ - protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos, - final int endPos) { - final StrLookup resolver = getVariableResolver(); - if (resolver == null) { - return null; - } - return resolver.lookup(variableName); - } - - // Escape - // ----------------------------------------------------------------------- - /** - * Returns the escape character. - * - * @return the character used for escaping variable references - */ - public char getEscapeChar() { - return this.escapeChar; - } - - /** - * Sets the escape character. If this character is placed before a variable - * reference in the source text, this variable will be ignored. - * - * @param escapeCharacter the escape character (0 for disabling escaping) - */ - public void setEscapeChar(final char escapeCharacter) { - this.escapeChar = escapeCharacter; - } - - // Prefix - // ----------------------------------------------------------------------- - /** - * Gets the variable prefix matcher currently in use. - *

- * The variable prefix is the character or characters that identify the start of - * a variable. This prefix is expressed in terms of a matcher allowing advanced - * prefix matches. - * - * @return the prefix matcher in use - */ - public StrMatcher getVariablePrefixMatcher() { - return prefixMatcher; - } - - /** - * Sets the variable prefix matcher currently in use. - *

- * The variable prefix is the character or characters that identify the start of - * a variable. This prefix is expressed in terms of a matcher allowing advanced - * prefix matches. - * - * @param prefixMatcher the prefix matcher to use, null ignored - * @return this, to enable chaining - * @throws IllegalArgumentException if the prefix matcher is null - */ - public StrSubstitutor setVariablePrefixMatcher(final StrMatcher prefixMatcher) { - if (prefixMatcher == null) { - throw new IllegalArgumentException("Variable prefix matcher must not be null."); - } - this.prefixMatcher = prefixMatcher; - return this; - } - - /** - * Sets the variable prefix to use. - *

- * The variable prefix is the character or characters that identify the start of - * a variable. This method allows a single character prefix to be easily set. - * - * @param prefix the prefix character to use - * @return this, to enable chaining - */ - public StrSubstitutor setVariablePrefix(final char prefix) { - return setVariablePrefixMatcher(StrMatcher.charMatcher(prefix)); - } - - /** - * Sets the variable prefix to use. - *

- * The variable prefix is the character or characters that identify the start of - * a variable. This method allows a string prefix to be easily set. - * - * @param prefix the prefix for variables, not null - * @return this, to enable chaining - * @throws IllegalArgumentException if the prefix is null - */ - public StrSubstitutor setVariablePrefix(final String prefix) { - if (prefix == null) { - throw new IllegalArgumentException("Variable prefix must not be null."); - } - return setVariablePrefixMatcher(StrMatcher.stringMatcher(prefix)); - } - - // Suffix - // ----------------------------------------------------------------------- - /** - * Gets the variable suffix matcher currently in use. - *

- * The variable suffix is the character or characters that identify the end of a - * variable. This suffix is expressed in terms of a matcher allowing advanced - * suffix matches. - * - * @return the suffix matcher in use - */ - public StrMatcher getVariableSuffixMatcher() { - return suffixMatcher; - } - - /** - * Sets the variable suffix matcher currently in use. - *

- * The variable suffix is the character or characters that identify the end of a - * variable. This suffix is expressed in terms of a matcher allowing advanced - * suffix matches. - * - * @param suffixMatcher the suffix matcher to use, null ignored - * @return this, to enable chaining - * @throws IllegalArgumentException if the suffix matcher is null - */ - public StrSubstitutor setVariableSuffixMatcher(final StrMatcher suffixMatcher) { - if (suffixMatcher == null) { - throw new IllegalArgumentException("Variable suffix matcher must not be null."); - } - this.suffixMatcher = suffixMatcher; - return this; - } - - /** - * Sets the variable suffix to use. - *

- * The variable suffix is the character or characters that identify the end of a - * variable. This method allows a single character suffix to be easily set. - * - * @param suffix the suffix character to use - * @return this, to enable chaining - */ - public StrSubstitutor setVariableSuffix(final char suffix) { - return setVariableSuffixMatcher(StrMatcher.charMatcher(suffix)); - } - - /** - * Sets the variable suffix to use. - *

- * The variable suffix is the character or characters that identify the end of a - * variable. This method allows a string suffix to be easily set. - * - * @param suffix the suffix for variables, not null - * @return this, to enable chaining - * @throws IllegalArgumentException if the suffix is null - */ - public StrSubstitutor setVariableSuffix(final String suffix) { - if (suffix == null) { - throw new IllegalArgumentException("Variable suffix must not be null."); - } - return setVariableSuffixMatcher(StrMatcher.stringMatcher(suffix)); - } - - // Variable Default Value Delimiter - // ----------------------------------------------------------------------- - /** - * Gets the variable default value delimiter matcher currently in use. - *

- * The variable default value delimiter is the character or characters that - * delimit the variable name and the variable default value. This delimiter is - * expressed in terms of a matcher allowing advanced variable default value - * delimiter matches. - *

- * If it returns null, then the variable default value resolution is disabled. - * - * @return the variable default value delimiter matcher in use, may be null - * @since 3.2 - */ - public StrMatcher getValueDelimiterMatcher() { - return valueDelimiterMatcher; - } - - /** - * Sets the variable default value delimiter matcher to use. - *

- * The variable default value delimiter is the character or characters that - * delimit the variable name and the variable default value. This delimiter is - * expressed in terms of a matcher allowing advanced variable default value - * delimiter matches. - *

- * If the {@code valueDelimiterMatcher} is null, then the variable default value - * resolution becomes disabled. - * - * @param valueDelimiterMatcher variable default value delimiter matcher to use, - * may be null - * @return this, to enable chaining - * @since 3.2 - */ - public StrSubstitutor setValueDelimiterMatcher(final StrMatcher valueDelimiterMatcher) { - this.valueDelimiterMatcher = valueDelimiterMatcher; - return this; - } - - /** - * Sets the variable default value delimiter to use. - *

- * The variable default value delimiter is the character or characters that - * delimit the variable name and the variable default value. This method allows - * a single character variable default value delimiter to be easily set. - * - * @param valueDelimiter the variable default value delimiter character to use - * @return this, to enable chaining - * @since 3.2 - */ - public StrSubstitutor setValueDelimiter(final char valueDelimiter) { - return setValueDelimiterMatcher(StrMatcher.charMatcher(valueDelimiter)); - } - - /** - * Sets the variable default value delimiter to use. - *

- * The variable default value delimiter is the character or characters that - * delimit the variable name and the variable default value. This method allows - * a string variable default value delimiter to be easily set. - *

- * If the {@code valueDelimiter} is null or empty string, then the variable - * default value resolution becomes disabled. - * - * @param valueDelimiter the variable default value delimiter string to use, may - * be null or empty - * @return this, to enable chaining - * @since 3.2 - */ - public StrSubstitutor setValueDelimiter(final String valueDelimiter) { - if (StringUtils.isEmpty(valueDelimiter)) { - setValueDelimiterMatcher(null); - return this; - } - return setValueDelimiterMatcher(StrMatcher.stringMatcher(valueDelimiter)); - } - - // Resolver - // ----------------------------------------------------------------------- - /** - * Gets the VariableResolver that is used to lookup variables. - * - * @return the VariableResolver - */ - public StrLookup getVariableResolver() { - return this.variableResolver; - } - - /** - * Sets the VariableResolver that is used to lookup variables. - * - * @param variableResolver the VariableResolver - */ - public void setVariableResolver(final StrLookup variableResolver) { - this.variableResolver = variableResolver; - } - - // Substitution support in variable names - // ----------------------------------------------------------------------- - /** - * Returns a flag whether substitution is done in variable names. - * - * @return the substitution in variable names flag - * @since 3.0 - */ - public boolean isEnableSubstitutionInVariables() { - return enableSubstitutionInVariables; - } - - /** - * Sets a flag whether substitution is done in variable names. If set to - * true, the names of variables can contain other variables which are - * processed first before the original variable is evaluated, e.g. - * {@code ${jre-${java.version}}}. The default value is false. - * - * @param enableSubstitutionInVariables the new value of the flag - * @since 3.0 - */ - public void setEnableSubstitutionInVariables(final boolean enableSubstitutionInVariables) { - this.enableSubstitutionInVariables = enableSubstitutionInVariables; - } - - /** - * Returns the flag controlling whether escapes are preserved during - * substitution. - * - * @return the preserve escape flag - * @since 3.5 - */ - public boolean isPreserveEscapes() { - return preserveEscapes; - } - - /** - * Sets a flag controlling whether escapes are preserved during substitution. If - * set to true, the escape character is retained during substitution - * (e.g. {@code $${this-is-escaped}} remains {@code $${this-is-escaped}}). If - * set to false, the escape character is removed during substitution - * (e.g. {@code $${this-is-escaped}} becomes {@code ${this-is-escaped}}). The - * default value is false - * - * @param preserveEscapes true if escapes are to be preserved - * @since 3.5 - */ - public void setPreserveEscapes(final boolean preserveEscapes) { - this.preserveEscapes = preserveEscapes; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/text/StrTokenizer.java b/sources/main/java/org/apache/commons/lang3/text/StrTokenizer.java deleted file mode 100644 index 2f116bd4..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/StrTokenizer.java +++ /dev/null @@ -1,1126 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.ListIterator; -import java.util.NoSuchElementException; - -import org.apache.commons.lang3.StringUtils; - -/** - * Tokenizes a string based on delimiters (separators) and supporting quoting - * and ignored character concepts. - *

- * This class can split a String into many smaller strings. It aims to do a - * similar job to {@link java.util.StringTokenizer StringTokenizer}, however it - * offers much more control and flexibility including implementing the - * {@code ListIterator} interface. By default, it is set up like - * {@code StringTokenizer}. - *

- * The input String is split into a number of tokens. Each token is - * separated from the next String by a delimiter. One or more delimiter - * characters must be specified. - *

- * Each token may be surrounded by quotes. The quote matcher specifies - * the quote character(s). A quote may be escaped within a quoted section by - * duplicating itself. - *

- * Between each token and the delimiter are potentially characters that need - * trimming. The trimmer matcher specifies these characters. One usage - * might be to trim whitespace characters. - *

- * At any point outside the quotes there might potentially be invalid - * characters. The ignored matcher specifies these characters to be - * removed. One usage might be to remove new line characters. - *

- * Empty tokens may be removed or returned as null. - * - *

- * "a,b,c"         - Three tokens "a","b","c"   (comma delimiter)
- * " a, b , c "    - Three tokens "a","b","c"   (default CSV processing trims whitespace)
- * "a, ", b ,", c" - Three tokens "a, " , " b ", ", c" (quoted text untouched)
- * 
- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
StrTokenizer properties and options
PropertyTypeDefault
delimCharSetMatcher{ \t\n\r\f}
quoteNoneMatcher{}
ignoreNoneMatcher{}
emptyTokenAsNullbooleanfalse
ignoreEmptyTokensbooleantrue
- * - * @since 2.2 - * @!deprecated as of 3.6, use commons-text - * StringTokenizer instead - */ -//@Deprecated -public class StrTokenizer implements ListIterator, Cloneable { - - private static final StrTokenizer CSV_TOKENIZER_PROTOTYPE; - private static final StrTokenizer TSV_TOKENIZER_PROTOTYPE; - static { - CSV_TOKENIZER_PROTOTYPE = new StrTokenizer(); - CSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.commaMatcher()); - CSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher()); - CSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher()); - CSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher()); - CSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false); - CSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false); - - TSV_TOKENIZER_PROTOTYPE = new StrTokenizer(); - TSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.tabMatcher()); - TSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher()); - TSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher()); - TSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher()); - TSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false); - TSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false); - } - - /** The text to work on. */ - private char[] chars; - /** The parsed tokens */ - private String[] tokens; - /** The current iteration position */ - private int tokenPos; - - /** The delimiter matcher */ - private StrMatcher delimMatcher = StrMatcher.splitMatcher(); - /** The quote matcher */ - private StrMatcher quoteMatcher = StrMatcher.noneMatcher(); - /** The ignored matcher */ - private StrMatcher ignoredMatcher = StrMatcher.noneMatcher(); - /** The trimmer matcher */ - private StrMatcher trimmerMatcher = StrMatcher.noneMatcher(); - - /** Whether to return empty tokens as null */ - private boolean emptyAsNull; - /** Whether to ignore empty tokens */ - private boolean ignoreEmptyTokens = true; - - // ----------------------------------------------------------------------- - - /** - * Returns a clone of {@code CSV_TOKENIZER_PROTOTYPE}. - * - * @return a clone of {@code CSV_TOKENIZER_PROTOTYPE}. - */ - private static StrTokenizer getCSVClone() { - return (StrTokenizer) CSV_TOKENIZER_PROTOTYPE.clone(); - } - - /** - * Gets a new tokenizer instance which parses Comma Separated Value strings - * initializing it with the given input. The default for CSV processing will be - * trim whitespace from both ends (which can be overridden with the setTrimmer - * method). - *

- * You must call a "reset" method to set the string which you want to parse. - * - * @return a new tokenizer instance which parses Comma Separated Value strings - */ - public static StrTokenizer getCSVInstance() { - return getCSVClone(); - } - - /** - * Gets a new tokenizer instance which parses Comma Separated Value strings - * initializing it with the given input. The default for CSV processing will be - * trim whitespace from both ends (which can be overridden with the setTrimmer - * method). - * - * @param input the text to parse - * @return a new tokenizer instance which parses Comma Separated Value strings - */ - public static StrTokenizer getCSVInstance(final String input) { - final StrTokenizer tok = getCSVClone(); - tok.reset(input); - return tok; - } - - /** - * Gets a new tokenizer instance which parses Comma Separated Value strings - * initializing it with the given input. The default for CSV processing will be - * trim whitespace from both ends (which can be overridden with the setTrimmer - * method). - * - * @param input the text to parse - * @return a new tokenizer instance which parses Comma Separated Value strings - */ - public static StrTokenizer getCSVInstance(final char[] input) { - final StrTokenizer tok = getCSVClone(); - tok.reset(input); - return tok; - } - - /** - * Returns a clone of {@code TSV_TOKENIZER_PROTOTYPE}. - * - * @return a clone of {@code TSV_TOKENIZER_PROTOTYPE}. - */ - private static StrTokenizer getTSVClone() { - return (StrTokenizer) TSV_TOKENIZER_PROTOTYPE.clone(); - } - - /** - * Gets a new tokenizer instance which parses Tab Separated Value strings. The - * default for CSV processing will be trim whitespace from both ends (which can - * be overridden with the setTrimmer method). - *

- * You must call a "reset" method to set the string which you want to parse. - * - * @return a new tokenizer instance which parses Tab Separated Value strings. - */ - public static StrTokenizer getTSVInstance() { - return getTSVClone(); - } - - /** - * Gets a new tokenizer instance which parses Tab Separated Value strings. The - * default for CSV processing will be trim whitespace from both ends (which can - * be overridden with the setTrimmer method). - * - * @param input the string to parse - * @return a new tokenizer instance which parses Tab Separated Value strings. - */ - public static StrTokenizer getTSVInstance(final String input) { - final StrTokenizer tok = getTSVClone(); - tok.reset(input); - return tok; - } - - /** - * Gets a new tokenizer instance which parses Tab Separated Value strings. The - * default for CSV processing will be trim whitespace from both ends (which can - * be overridden with the setTrimmer method). - * - * @param input the string to parse - * @return a new tokenizer instance which parses Tab Separated Value strings. - */ - public static StrTokenizer getTSVInstance(final char[] input) { - final StrTokenizer tok = getTSVClone(); - tok.reset(input); - return tok; - } - - // ----------------------------------------------------------------------- - /** - * Constructs a tokenizer splitting on space, tab, newline and formfeed as per - * StringTokenizer, but with no text to tokenize. - *

- * This constructor is normally used with {@link #reset(String)}. - */ - public StrTokenizer() { - this.chars = null; - } - - /** - * Constructs a tokenizer splitting on space, tab, newline and formfeed as per - * StringTokenizer. - * - * @param input the string which is to be parsed - */ - public StrTokenizer(final String input) { - if (input != null) { - chars = input.toCharArray(); - } else { - chars = null; - } - } - - /** - * Constructs a tokenizer splitting on the specified delimiter character. - * - * @param input the string which is to be parsed - * @param delim the field delimiter character - */ - public StrTokenizer(final String input, final char delim) { - this(input); - setDelimiterChar(delim); - } - - /** - * Constructs a tokenizer splitting on the specified delimiter string. - * - * @param input the string which is to be parsed - * @param delim the field delimiter string - */ - public StrTokenizer(final String input, final String delim) { - this(input); - setDelimiterString(delim); - } - - /** - * Constructs a tokenizer splitting using the specified delimiter matcher. - * - * @param input the string which is to be parsed - * @param delim the field delimiter matcher - */ - public StrTokenizer(final String input, final StrMatcher delim) { - this(input); - setDelimiterMatcher(delim); - } - - /** - * Constructs a tokenizer splitting on the specified delimiter character and - * handling quotes using the specified quote character. - * - * @param input the string which is to be parsed - * @param delim the field delimiter character - * @param quote the field quoted string character - */ - public StrTokenizer(final String input, final char delim, final char quote) { - this(input, delim); - setQuoteChar(quote); - } - - /** - * Constructs a tokenizer splitting using the specified delimiter matcher and - * handling quotes using the specified quote matcher. - * - * @param input the string which is to be parsed - * @param delim the field delimiter matcher - * @param quote the field quoted string matcher - */ - public StrTokenizer(final String input, final StrMatcher delim, final StrMatcher quote) { - this(input, delim); - setQuoteMatcher(quote); - } - - /** - * Constructs a tokenizer splitting on space, tab, newline and formfeed as per - * StringTokenizer. - * - * @param input the string which is to be parsed, not cloned - */ - public StrTokenizer(final char[] input) { - this.chars = new String(input).toCharArray(); - } - - /** - * Constructs a tokenizer splitting on the specified character. - * - * @param input the string which is to be parsed, not cloned - * @param delim the field delimiter character - */ - public StrTokenizer(final char[] input, final char delim) { - this(input); - setDelimiterChar(delim); - } - - /** - * Constructs a tokenizer splitting on the specified string. - * - * @param input the string which is to be parsed, not cloned - * @param delim the field delimiter string - */ - public StrTokenizer(final char[] input, final String delim) { - this(input); - setDelimiterString(delim); - } - - /** - * Constructs a tokenizer splitting using the specified delimiter matcher. - * - * @param input the string which is to be parsed, not cloned - * @param delim the field delimiter matcher - */ - public StrTokenizer(final char[] input, final StrMatcher delim) { - this(input); - setDelimiterMatcher(delim); - } - - /** - * Constructs a tokenizer splitting on the specified delimiter character and - * handling quotes using the specified quote character. - * - * @param input the string which is to be parsed, not cloned - * @param delim the field delimiter character - * @param quote the field quoted string character - */ - public StrTokenizer(final char[] input, final char delim, final char quote) { - this(input, delim); - setQuoteChar(quote); - } - - /** - * Constructs a tokenizer splitting using the specified delimiter matcher and - * handling quotes using the specified quote matcher. - * - * @param input the string which is to be parsed, not cloned - * @param delim the field delimiter character - * @param quote the field quoted string character - */ - public StrTokenizer(final char[] input, final StrMatcher delim, final StrMatcher quote) { - this(input, delim); - setQuoteMatcher(quote); - } - - // API - // ----------------------------------------------------------------------- - /** - * Gets the number of tokens found in the String. - * - * @return the number of matched tokens - */ - public int size() { - checkTokenized(); - return tokens.length; - } - - /** - * Gets the next token from the String. Equivalent to {@link #next()} except it - * returns null rather than throwing {@link NoSuchElementException} when no - * tokens remain. - * - * @return the next sequential token, or null when no more tokens are found - */ - public String nextToken() { - if (hasNext()) { - return tokens[tokenPos++]; - } - return null; - } - - /** - * Gets the previous token from the String. - * - * @return the previous sequential token, or null when no more tokens are found - */ - public String previousToken() { - if (hasPrevious()) { - return tokens[--tokenPos]; - } - return null; - } - - /** - * Gets a copy of the full token list as an independent modifiable array. - * - * @return the tokens as a String array - */ - public String[] getTokenArray() { - checkTokenized(); - return tokens.clone(); - } - - /** - * Gets a copy of the full token list as an independent modifiable list. - * - * @return the tokens as a String array - */ - public List getTokenList() { - checkTokenized(); - final List list = new ArrayList<>(tokens.length); - list.addAll(Arrays.asList(tokens)); - return list; - } - - /** - * Resets this tokenizer, forgetting all parsing and iteration already - * completed. - *

- * This method allows the same tokenizer to be reused for the same String. - * - * @return this, to enable chaining - */ - public StrTokenizer reset() { - tokenPos = 0; - tokens = null; - return this; - } - - /** - * Reset this tokenizer, giving it a new input string to parse. In this manner - * you can re-use a tokenizer with the same settings on multiple input lines. - * - * @param input the new string to tokenize, null sets no text to parse - * @return this, to enable chaining - */ - public StrTokenizer reset(final String input) { - reset(); - if (input != null) { - this.chars = input.toCharArray(); - } else { - this.chars = null; - } - return this; - } - - /** - * Reset this tokenizer, giving it a new input string to parse. In this manner - * you can re-use a tokenizer with the same settings on multiple input lines. - * - * @param input the new character array to tokenize, not cloned, null sets no - * text to parse - * @return this, to enable chaining - */ - public StrTokenizer reset(final char[] input) { - reset(); - this.chars = new String(input).toCharArray(); - return this; - } - - // ListIterator - // ----------------------------------------------------------------------- - /** - * Checks whether there are any more tokens. - * - * @return true if there are more tokens - */ - @Override - public boolean hasNext() { - checkTokenized(); - return tokenPos < tokens.length; - } - - /** - * Gets the next token. - * - * @return the next String token - * @throws NoSuchElementException if there are no more elements - */ - @Override - public String next() { - if (hasNext()) { - return tokens[tokenPos++]; - } - throw new NoSuchElementException(); - } - - /** - * Gets the index of the next token to return. - * - * @return the next token index - */ - @Override - public int nextIndex() { - return tokenPos; - } - - /** - * Checks whether there are any previous tokens that can be iterated to. - * - * @return true if there are previous tokens - */ - @Override - public boolean hasPrevious() { - checkTokenized(); - return tokenPos > 0; - } - - /** - * Gets the token previous to the last returned token. - * - * @return the previous token - */ - @Override - public String previous() { - if (hasPrevious()) { - return tokens[--tokenPos]; - } - throw new NoSuchElementException(); - } - - /** - * Gets the index of the previous token. - * - * @return the previous token index - */ - @Override - public int previousIndex() { - return tokenPos - 1; - } - - /** - * Unsupported ListIterator operation. - * - * @throws UnsupportedOperationException always - */ - @Override - public void remove() { - throw new UnsupportedOperationException("remove() is unsupported"); - } - - /** - * Unsupported ListIterator operation. - * - * @param obj this parameter ignored. - * @throws UnsupportedOperationException always - */ - @Override - public void set(final String obj) { - throw new UnsupportedOperationException("set() is unsupported"); - } - - /** - * Unsupported ListIterator operation. - * - * @param obj this parameter ignored. - * @throws UnsupportedOperationException always - */ - @Override - public void add(final String obj) { - throw new UnsupportedOperationException("add() is unsupported"); - } - - // Implementation - // ----------------------------------------------------------------------- - /** - * Checks if tokenization has been done, and if not then do it. - */ - private void checkTokenized() { - if (tokens == null) { - if (chars == null) { - // still call tokenize as subclass may do some work - final List split = tokenize(null, 0, 0); - tokens = split.toArray(new String[0]); - } else { - final List split = tokenize(chars, 0, chars.length); - tokens = split.toArray(new String[0]); - } - } - } - - /** - * Internal method to performs the tokenization. - *

- * Most users of this class do not need to call this method. This method will be - * called automatically by other (public) methods when required. - *

- * This method exists to allow subclasses to add code before or after the - * tokenization. For example, a subclass could alter the character array, offset - * or count to be parsed, or call the tokenizer multiple times on multiple - * strings. It is also be possible to filter the results. - *

- * {@code StrTokenizer} will always pass a zero offset and a count equal to the - * length of the array to this method, however a subclass may pass other values, - * or even an entirely different array. - * - * @param srcChars the character array being tokenized, may be null - * @param offset the start position within the character array, must be valid - * @param count the number of characters to tokenize, must be valid - * @return the modifiable list of String tokens, unmodifiable if null array or - * zero count - */ - protected List tokenize(final char[] srcChars, final int offset, final int count) { - if (srcChars == null || count == 0) { - return Collections.emptyList(); - } - final StrBuilder buf = new StrBuilder(); - final List tokenList = new ArrayList<>(); - int pos = offset; - - // loop around the entire buffer - while (pos >= 0 && pos < count) { - // find next token - pos = readNextToken(srcChars, pos, count, buf, tokenList); - - // handle case where end of string is a delimiter - if (pos >= count) { - addToken(tokenList, StringUtils.EMPTY); - } - } - return tokenList; - } - - /** - * Adds a token to a list, paying attention to the parameters we've set. - * - * @param list the list to add to - * @param tok the token to add - */ - private void addToken(final List list, String tok) { - if (StringUtils.isEmpty(tok)) { - if (isIgnoreEmptyTokens()) { - return; - } - if (isEmptyTokenAsNull()) { - tok = null; - } - } - list.add(tok); - } - - /** - * Reads character by character through the String to get the next token. - * - * @param srcChars the character array being tokenized - * @param start the first character of field - * @param len the length of the character array being tokenized - * @param workArea a temporary work area - * @param tokenList the list of parsed tokens - * @return the starting position of the next field (the character immediately - * after the delimiter), or -1 if end of string found - */ - private int readNextToken(final char[] srcChars, int start, final int len, final StrBuilder workArea, - final List tokenList) { - // skip all leading whitespace, unless it is the - // field delimiter or the quote character - while (start < len) { - final int removeLen = Math.max(getIgnoredMatcher().isMatch(srcChars, start, start, len), - getTrimmerMatcher().isMatch(srcChars, start, start, len)); - if (removeLen == 0 || getDelimiterMatcher().isMatch(srcChars, start, start, len) > 0 - || getQuoteMatcher().isMatch(srcChars, start, start, len) > 0) { - break; - } - start += removeLen; - } - - // handle reaching end - if (start >= len) { - addToken(tokenList, StringUtils.EMPTY); - return -1; - } - - // handle empty token - final int delimLen = getDelimiterMatcher().isMatch(srcChars, start, start, len); - if (delimLen > 0) { - addToken(tokenList, StringUtils.EMPTY); - return start + delimLen; - } - - // handle found token - final int quoteLen = getQuoteMatcher().isMatch(srcChars, start, start, len); - if (quoteLen > 0) { - return readWithQuotes(srcChars, start + quoteLen, len, workArea, tokenList, start, quoteLen); - } - return readWithQuotes(srcChars, start, len, workArea, tokenList, 0, 0); - } - - /** - * Reads a possibly quoted string token. - * - * @param srcChars the character array being tokenized - * @param start the first character of field - * @param len the length of the character array being tokenized - * @param workArea a temporary work area - * @param tokenList the list of parsed tokens - * @param quoteStart the start position of the matched quote, 0 if no quoting - * @param quoteLen the length of the matched quote, 0 if no quoting - * @return the starting position of the next field (the character immediately - * after the delimiter, or if end of string found, then the length of - * string - */ - private int readWithQuotes(final char[] srcChars, final int start, final int len, final StrBuilder workArea, - final List tokenList, final int quoteStart, final int quoteLen) { - // Loop until we've found the end of the quoted - // string or the end of the input - workArea.clear(); - int pos = start; - boolean quoting = quoteLen > 0; - int trimStart = 0; - - while (pos < len) { - // quoting mode can occur several times throughout a string - // we must switch between quoting and non-quoting until we - // encounter a non-quoted delimiter, or end of string - if (quoting) { - // In quoting mode - - // If we've found a quote character, see if it's - // followed by a second quote. If so, then we need - // to actually put the quote character into the token - // rather than end the token. - if (isQuote(srcChars, pos, len, quoteStart, quoteLen)) { - if (isQuote(srcChars, pos + quoteLen, len, quoteStart, quoteLen)) { - // matched pair of quotes, thus an escaped quote - workArea.append(srcChars, pos, quoteLen); - pos += quoteLen * 2; - trimStart = workArea.size(); - continue; - } - - // end of quoting - quoting = false; - pos += quoteLen; - continue; - } - - // copy regular character from inside quotes - workArea.append(srcChars[pos++]); - trimStart = workArea.size(); - - } else { - // Not in quoting mode - - // check for delimiter, and thus end of token - final int delimLen = getDelimiterMatcher().isMatch(srcChars, pos, start, len); - if (delimLen > 0) { - // return condition when end of token found - addToken(tokenList, workArea.substring(0, trimStart)); - return pos + delimLen; - } - - // check for quote, and thus back into quoting mode - if (quoteLen > 0 && isQuote(srcChars, pos, len, quoteStart, quoteLen)) { - quoting = true; - pos += quoteLen; - continue; - } - - // check for ignored (outside quotes), and ignore - final int ignoredLen = getIgnoredMatcher().isMatch(srcChars, pos, start, len); - if (ignoredLen > 0) { - pos += ignoredLen; - continue; - } - - // check for trimmed character - // don't yet know if its at the end, so copy to workArea - // use trimStart to keep track of trim at the end - final int trimmedLen = getTrimmerMatcher().isMatch(srcChars, pos, start, len); - if (trimmedLen > 0) { - workArea.append(srcChars, pos, trimmedLen); - pos += trimmedLen; - continue; - } - - // copy regular character from outside quotes - workArea.append(srcChars[pos++]); - trimStart = workArea.size(); - } - } - - // return condition when end of string found - addToken(tokenList, workArea.substring(0, trimStart)); - return -1; - } - - /** - * Checks if the characters at the index specified match the quote already - * matched in readNextToken(). - * - * @param srcChars the character array being tokenized - * @param pos the position to check for a quote - * @param len the length of the character array being tokenized - * @param quoteStart the start position of the matched quote, 0 if no quoting - * @param quoteLen the length of the matched quote, 0 if no quoting - * @return true if a quote is matched - */ - private boolean isQuote(final char[] srcChars, final int pos, final int len, final int quoteStart, - final int quoteLen) { - for (int i = 0; i < quoteLen; i++) { - if (pos + i >= len || srcChars[pos + i] != srcChars[quoteStart + i]) { - return false; - } - } - return true; - } - - // Delimiter - // ----------------------------------------------------------------------- - /** - * Gets the field delimiter matcher. - * - * @return the delimiter matcher in use - */ - public StrMatcher getDelimiterMatcher() { - return this.delimMatcher; - } - - /** - * Sets the field delimiter matcher. - *

- * The delimiter is used to separate one token from another. - * - * @param delim the delimiter matcher to use - * @return this, to enable chaining - */ - public StrTokenizer setDelimiterMatcher(final StrMatcher delim) { - if (delim == null) { - this.delimMatcher = StrMatcher.noneMatcher(); - } else { - this.delimMatcher = delim; - } - return this; - } - - /** - * Sets the field delimiter character. - * - * @param delim the delimiter character to use - * @return this, to enable chaining - */ - public StrTokenizer setDelimiterChar(final char delim) { - return setDelimiterMatcher(StrMatcher.charMatcher(delim)); - } - - /** - * Sets the field delimiter string. - * - * @param delim the delimiter string to use - * @return this, to enable chaining - */ - public StrTokenizer setDelimiterString(final String delim) { - return setDelimiterMatcher(StrMatcher.stringMatcher(delim)); - } - - // Quote - // ----------------------------------------------------------------------- - /** - * Gets the quote matcher currently in use. - *

- * The quote character is used to wrap data between the tokens. This enables - * delimiters to be entered as data. The default value is '"' (double quote). - * - * @return the quote matcher in use - */ - public StrMatcher getQuoteMatcher() { - return quoteMatcher; - } - - /** - * Set the quote matcher to use. - *

- * The quote character is used to wrap data between the tokens. This enables - * delimiters to be entered as data. - * - * @param quote the quote matcher to use, null ignored - * @return this, to enable chaining - */ - public StrTokenizer setQuoteMatcher(final StrMatcher quote) { - if (quote != null) { - this.quoteMatcher = quote; - } - return this; - } - - /** - * Sets the quote character to use. - *

- * The quote character is used to wrap data between the tokens. This enables - * delimiters to be entered as data. - * - * @param quote the quote character to use - * @return this, to enable chaining - */ - public StrTokenizer setQuoteChar(final char quote) { - return setQuoteMatcher(StrMatcher.charMatcher(quote)); - } - - // Ignored - // ----------------------------------------------------------------------- - /** - * Gets the ignored character matcher. - *

- * These characters are ignored when parsing the String, unless they are within - * a quoted region. The default value is not to ignore anything. - * - * @return the ignored matcher in use - */ - public StrMatcher getIgnoredMatcher() { - return ignoredMatcher; - } - - /** - * Set the matcher for characters to ignore. - *

- * These characters are ignored when parsing the String, unless they are within - * a quoted region. - * - * @param ignored the ignored matcher to use, null ignored - * @return this, to enable chaining - */ - public StrTokenizer setIgnoredMatcher(final StrMatcher ignored) { - if (ignored != null) { - this.ignoredMatcher = ignored; - } - return this; - } - - /** - * Set the character to ignore. - *

- * This character is ignored when parsing the String, unless it is within a - * quoted region. - * - * @param ignored the ignored character to use - * @return this, to enable chaining - */ - public StrTokenizer setIgnoredChar(final char ignored) { - return setIgnoredMatcher(StrMatcher.charMatcher(ignored)); - } - - // Trimmer - // ----------------------------------------------------------------------- - /** - * Gets the trimmer character matcher. - *

- * These characters are trimmed off on each side of the delimiter until the - * token or quote is found. The default value is not to trim anything. - * - * @return the trimmer matcher in use - */ - public StrMatcher getTrimmerMatcher() { - return trimmerMatcher; - } - - /** - * Sets the matcher for characters to trim. - *

- * These characters are trimmed off on each side of the delimiter until the - * token or quote is found. - * - * @param trimmer the trimmer matcher to use, null ignored - * @return this, to enable chaining - */ - public StrTokenizer setTrimmerMatcher(final StrMatcher trimmer) { - if (trimmer != null) { - this.trimmerMatcher = trimmer; - } - return this; - } - - // ----------------------------------------------------------------------- - /** - * Gets whether the tokenizer currently returns empty tokens as null. The - * default for this property is false. - * - * @return true if empty tokens are returned as null - */ - public boolean isEmptyTokenAsNull() { - return this.emptyAsNull; - } - - /** - * Sets whether the tokenizer should return empty tokens as null. The default - * for this property is false. - * - * @param emptyAsNull whether empty tokens are returned as null - * @return this, to enable chaining - */ - public StrTokenizer setEmptyTokenAsNull(final boolean emptyAsNull) { - this.emptyAsNull = emptyAsNull; - return this; - } - - // ----------------------------------------------------------------------- - /** - * Gets whether the tokenizer currently ignores empty tokens. The default for - * this property is true. - * - * @return true if empty tokens are not returned - */ - public boolean isIgnoreEmptyTokens() { - return ignoreEmptyTokens; - } - - /** - * Sets whether the tokenizer should ignore and not return empty tokens. The - * default for this property is true. - * - * @param ignoreEmptyTokens whether empty tokens are not returned - * @return this, to enable chaining - */ - public StrTokenizer setIgnoreEmptyTokens(final boolean ignoreEmptyTokens) { - this.ignoreEmptyTokens = ignoreEmptyTokens; - return this; - } - - // ----------------------------------------------------------------------- - /** - * Gets the String content that the tokenizer is parsing. - * - * @return the string content being parsed - */ - public String getContent() { - if (chars == null) { - return null; - } - return new String(chars); - } - - // ----------------------------------------------------------------------- - /** - * Creates a new instance of this Tokenizer. The new instance is reset so that - * it will be at the start of the token list. If a - * {@link CloneNotSupportedException} is caught, return {@code null}. - * - * @return a new instance of this Tokenizer which has been reset. - */ - @Override - public Object clone() { - try { - return cloneReset(); - } catch (final CloneNotSupportedException ex) { - return null; - } - } - - /** - * Creates a new instance of this Tokenizer. The new instance is reset so that - * it will be at the start of the token list. - * - * @return a new instance of this Tokenizer which has been reset. - * @throws CloneNotSupportedException if there is a problem cloning - */ - Object cloneReset() throws CloneNotSupportedException { - // this method exists to enable 100% test coverage - final StrTokenizer cloned = (StrTokenizer) super.clone(); - if (cloned.chars != null) { - cloned.chars = cloned.chars.clone(); - } - cloned.reset(); - return cloned; - } - - // ----------------------------------------------------------------------- - /** - * Gets the String content that the tokenizer is parsing. - * - * @return the string content being parsed - */ - @Override - public String toString() { - if (tokens == null) { - return "StrTokenizer[not tokenized yet]"; - } - return "StrTokenizer" + getTokenList(); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/WordUtils.java b/sources/main/java/org/apache/commons/lang3/text/WordUtils.java deleted file mode 100644 index 68a30a71..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/WordUtils.java +++ /dev/null @@ -1,833 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; - -/** - *

- * Operations on Strings that contain words. - *

- * - *

- * This class tries to handle {@code null} input gracefully. An exception will - * not be thrown for a {@code null} input. Each method documents its behavior in - * more detail. - *

- * - * @since 2.0 - * @!deprecated as of 3.6, use commons-text - * WordUtils instead - */ -//@Deprecated -public class WordUtils { - - /** - *

- * {@code WordUtils} instances should NOT be constructed in standard - * programming. Instead, the class should be used as - * {@code WordUtils.wrap("foo bar", 20);}. - *

- * - *

- * This constructor is public to permit tools that require a JavaBean instance - * to operate. - *

- */ - public WordUtils() { - } - - // Wrapping - // -------------------------------------------------------------------------- - /** - *

- * Wraps a single line of text, identifying words by {@code ' '}. - *

- * - *

- * New lines will be separated by the system property line separator. Very long - * words, such as URLs will not be wrapped. - *

- * - *

- * Leading spaces on a new line are stripped. Trailing spaces are not stripped. - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Examples
inputwrapLengthresult
null*null
""*""
"Here is one line of text that is going to be wrapped after 20 - * columns."20"Here is one line of\ntext that is going\nto be wrapped after\n20 - * columns."
"Click here to jump to the commons website - - * https://commons.apache.org"20"Click here to jump\nto the commons\nwebsite - * -\nhttps://commons.apache.org"
"Click here, https://commons.apache.org, to jump to the commons - * website"20"Click here,\nhttps://commons.apache.org,\nto jump to the\ncommons - * website"
- * - * (assuming that '\n' is the systems line separator) - * - * @param str the String to be word wrapped, may be null - * @param wrapLength the column to wrap the words at, less than 1 is treated as - * 1 - * @return a line with newlines inserted, {@code null} if null input - */ - public static String wrap(final String str, final int wrapLength) { - return wrap(str, wrapLength, null, false); - } - - /** - *

- * Wraps a single line of text, identifying words by {@code ' '}. - *

- * - *

- * Leading spaces on a new line are stripped. Trailing spaces are not stripped. - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Examples
inputwrapLengthnewLineStringwrapLongWordsresult
null**true/falsenull
""**true/false""
"Here is one line of text that is going to be wrapped after 20 - * columns."20"\n"true/false"Here is one line of\ntext that is going\nto be wrapped after\n20 - * columns."
"Here is one line of text that is going to be wrapped after 20 - * columns."20"<br />"true/false"Here is one line of<br />text that is going<br />to be - * wrapped after<br />20 columns."
"Here is one line of text that is going to be wrapped after 20 - * columns."20nulltrue/false"Here is one line of" + systemNewLine + "text that is going" + - * systemNewLine + "to be wrapped after" + systemNewLine + "20 columns."
"Click here to jump to the commons website - - * https://commons.apache.org"20"\n"false"Click here to jump\nto the commons\nwebsite - * -\nhttps://commons.apache.org"
"Click here to jump to the commons website - - * https://commons.apache.org"20"\n"true"Click here to jump\nto the commons\nwebsite - * -\nhttp://commons.apach\ne.org"
- * - * @param str the String to be word wrapped, may be null - * @param wrapLength the column to wrap the words at, less than 1 is treated - * as 1 - * @param newLineStr the string to insert for a new line, {@code null} uses - * the system property line separator - * @param wrapLongWords true if long words (such as URLs) should be wrapped - * @return a line with newlines inserted, {@code null} if null input - */ - public static String wrap(final String str, final int wrapLength, final String newLineStr, - final boolean wrapLongWords) { - return wrap(str, wrapLength, newLineStr, wrapLongWords, " "); - } - - /** - *

- * Wraps a single line of text, identifying words by {@code wrapOn}. - *

- * - *

- * Leading spaces on a new line are stripped. Trailing spaces are not stripped. - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Examples
inputwrapLengthnewLineStringwrapLongWordswrapOnresult
null**true/false*null
""**true/false*""
"Here is one line of text that is going to be wrapped after 20 - * columns."20"\n"true/false" ""Here is one line of\ntext that is going\nto be wrapped after\n20 - * columns."
"Here is one line of text that is going to be wrapped after 20 - * columns."20"<br />"true/false" ""Here is one line of<br />text that is going<br />to be - * wrapped after<br />20 columns."
"Here is one line of text that is going to be wrapped after 20 - * columns."20nulltrue/false" ""Here is one line of" + systemNewLine + "text that is going" + - * systemNewLine + "to be wrapped after" + systemNewLine + "20 columns."
"Click here to jump to the commons website - - * https://commons.apache.org"20"\n"false" ""Click here to jump\nto the commons\nwebsite - * -\nhttps://commons.apache.org"
"Click here to jump to the commons website - - * https://commons.apache.org"20"\n"true" ""Click here to jump\nto the commons\nwebsite - * -\nhttp://commons.apach\ne.org"
"flammable/inflammable"20"\n"true"/""flammable\ninflammable"
- * - * @param str the String to be word wrapped, may be null - * @param wrapLength the column to wrap the words at, less than 1 is treated - * as 1 - * @param newLineStr the string to insert for a new line, {@code null} uses - * the system property line separator - * @param wrapLongWords true if long words (such as URLs) should be wrapped - * @param wrapOn regex expression to be used as a breakable characters, - * if blank string is provided a space character will be - * used - * @return a line with newlines inserted, {@code null} if null input - */ - public static String wrap(final String str, int wrapLength, String newLineStr, final boolean wrapLongWords, - String wrapOn) { - if (str == null) { - return null; - } - if (newLineStr == null) { - newLineStr = System.lineSeparator(); - } - if (wrapLength < 1) { - wrapLength = 1; - } - if (StringUtils.isBlank(wrapOn)) { - wrapOn = " "; - } - final Pattern patternToWrapOn = Pattern.compile(wrapOn); - final int inputLineLength = str.length(); - int offset = 0; - final StringBuilder wrappedLine = new StringBuilder(inputLineLength + 32); - - while (offset < inputLineLength) { - int spaceToWrapAt = -1; - Matcher matcher = patternToWrapOn.matcher(str.substring(offset, - Math.min((int) Math.min(Integer.MAX_VALUE, offset + wrapLength + 1L), inputLineLength))); - if (matcher.find()) { - if (matcher.start() == 0) { - offset += matcher.end(); - continue; - } - spaceToWrapAt = matcher.start() + offset; - } - - // only last line without leading spaces is left - if (inputLineLength - offset <= wrapLength) { - break; - } - - while (matcher.find()) { - spaceToWrapAt = matcher.start() + offset; - } - - if (spaceToWrapAt >= offset) { - // normal case - wrappedLine.append(str, offset, spaceToWrapAt); - wrappedLine.append(newLineStr); - offset = spaceToWrapAt + 1; - - } else // really long word or URL - if (wrapLongWords) { - // wrap really long word one line at a time - wrappedLine.append(str, offset, wrapLength + offset); - wrappedLine.append(newLineStr); - offset += wrapLength; - } else { - // do not wrap really long word, just extend beyond limit - matcher = patternToWrapOn.matcher(str.substring(offset + wrapLength)); - if (matcher.find()) { - spaceToWrapAt = matcher.start() + offset + wrapLength; - } - - if (spaceToWrapAt >= 0) { - wrappedLine.append(str, offset, spaceToWrapAt); - wrappedLine.append(newLineStr); - offset = spaceToWrapAt + 1; - } else { - wrappedLine.append(str, offset, str.length()); - offset = inputLineLength; - } - } - } - - // Whatever is left in line is short enough to just pass through - wrappedLine.append(str, offset, str.length()); - - return wrappedLine.toString(); - } - - // Capitalizing - // ----------------------------------------------------------------------- - /** - *

- * Capitalizes all the whitespace separated words in a String. Only the first - * character of each word is changed. To convert the rest of each word to - * lowercase at the same time, use {@link #capitalizeFully(String)}. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null} - * input String returns {@code null}. Capitalization uses the Unicode title - * case, normally equivalent to upper case. - *

- * - *
-	 * WordUtils.capitalize(null)        = null
-	 * WordUtils.capitalize("")          = ""
-	 * WordUtils.capitalize("i am FINE") = "I Am FINE"
-	 * 
- * - * @param str the String to capitalize, may be null - * @return capitalized String, {@code null} if null String input - * @see #uncapitalize(String) - * @see #capitalizeFully(String) - */ - public static String capitalize(final String str) { - return capitalize(str, null); - } - - /** - *

- * Capitalizes all the delimiter separated words in a String. Only the first - * character of each word is changed. To convert the rest of each word to - * lowercase at the same time, use {@link #capitalizeFully(String, char[])}. - *

- * - *

- * The delimiters represent a set of characters understood to separate words. - * The first string character and the first non-delimiter character after a - * delimiter will be capitalized. - *

- * - *

- * A {@code null} input String returns {@code null}. Capitalization uses the - * Unicode title case, normally equivalent to upper case. - *

- * - *
-	 * WordUtils.capitalize(null, *)            = null
-	 * WordUtils.capitalize("", *)              = ""
-	 * WordUtils.capitalize(*, new char[0])     = *
-	 * WordUtils.capitalize("i am fine", null)  = "I Am Fine"
-	 * WordUtils.capitalize("i aM.fine", {'.'}) = "I aM.Fine"
-	 * 
- * - * @param str the String to capitalize, may be null - * @param delimiters set of characters to determine capitalization, null means - * whitespace - * @return capitalized String, {@code null} if null String input - * @see #uncapitalize(String) - * @see #capitalizeFully(String) - * @since 2.1 - */ - public static String capitalize(final String str, final char... delimiters) { - final int delimLen = delimiters == null ? -1 : delimiters.length; - if (StringUtils.isEmpty(str) || delimLen == 0) { - return str; - } - final char[] buffer = str.toCharArray(); - boolean capitalizeNext = true; - for (int i = 0; i < buffer.length; i++) { - final char ch = buffer[i]; - if (isDelimiter(ch, delimiters)) { - capitalizeNext = true; - } else if (capitalizeNext) { - buffer[i] = Character.toTitleCase(ch); - capitalizeNext = false; - } - } - return new String(buffer); - } - - // ----------------------------------------------------------------------- - /** - *

- * Converts all the whitespace separated words in a String into capitalized - * words, that is each word is made up of a titlecase character and then a - * series of lowercase characters. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null} - * input String returns {@code null}. Capitalization uses the Unicode title - * case, normally equivalent to upper case. - *

- * - *
-	 * WordUtils.capitalizeFully(null)        = null
-	 * WordUtils.capitalizeFully("")          = ""
-	 * WordUtils.capitalizeFully("i am FINE") = "I Am Fine"
-	 * 
- * - * @param str the String to capitalize, may be null - * @return capitalized String, {@code null} if null String input - */ - public static String capitalizeFully(final String str) { - return capitalizeFully(str, null); - } - - /** - *

- * Converts all the delimiter separated words in a String into capitalized - * words, that is each word is made up of a titlecase character and then a - * series of lowercase characters. - *

- * - *

- * The delimiters represent a set of characters understood to separate words. - * The first string character and the first non-delimiter character after a - * delimiter will be capitalized. - *

- * - *

- * A {@code null} input String returns {@code null}. Capitalization uses the - * Unicode title case, normally equivalent to upper case. - *

- * - *
-	 * WordUtils.capitalizeFully(null, *)            = null
-	 * WordUtils.capitalizeFully("", *)              = ""
-	 * WordUtils.capitalizeFully(*, null)            = *
-	 * WordUtils.capitalizeFully(*, new char[0])     = *
-	 * WordUtils.capitalizeFully("i aM.fine", {'.'}) = "I am.Fine"
-	 * 
- * - * @param str the String to capitalize, may be null - * @param delimiters set of characters to determine capitalization, null means - * whitespace - * @return capitalized String, {@code null} if null String input - * @since 2.1 - */ - public static String capitalizeFully(String str, final char... delimiters) { - final int delimLen = delimiters == null ? -1 : delimiters.length; - if (StringUtils.isEmpty(str) || delimLen == 0) { - return str; - } - str = str.toLowerCase(); - return capitalize(str, delimiters); - } - - // ----------------------------------------------------------------------- - /** - *

- * Uncapitalizes all the whitespace separated words in a String. Only the first - * character of each word is changed. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null} - * input String returns {@code null}. - *

- * - *
-	 * WordUtils.uncapitalize(null)        = null
-	 * WordUtils.uncapitalize("")          = ""
-	 * WordUtils.uncapitalize("I Am FINE") = "i am fINE"
-	 * 
- * - * @param str the String to uncapitalize, may be null - * @return uncapitalized String, {@code null} if null String input - * @see #capitalize(String) - */ - public static String uncapitalize(final String str) { - return uncapitalize(str, null); - } - - /** - *

- * Uncapitalizes all the whitespace separated words in a String. Only the first - * character of each word is changed. - *

- * - *

- * The delimiters represent a set of characters understood to separate words. - * The first string character and the first non-delimiter character after a - * delimiter will be uncapitalized. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null} - * input String returns {@code null}. - *

- * - *
-	 * WordUtils.uncapitalize(null, *)            = null
-	 * WordUtils.uncapitalize("", *)              = ""
-	 * WordUtils.uncapitalize(*, null)            = *
-	 * WordUtils.uncapitalize(*, new char[0])     = *
-	 * WordUtils.uncapitalize("I AM.FINE", {'.'}) = "i AM.fINE"
-	 * 
- * - * @param str the String to uncapitalize, may be null - * @param delimiters set of characters to determine uncapitalization, null means - * whitespace - * @return uncapitalized String, {@code null} if null String input - * @see #capitalize(String) - * @since 2.1 - */ - public static String uncapitalize(final String str, final char... delimiters) { - final int delimLen = delimiters == null ? -1 : delimiters.length; - if (StringUtils.isEmpty(str) || delimLen == 0) { - return str; - } - final char[] buffer = str.toCharArray(); - boolean uncapitalizeNext = true; - for (int i = 0; i < buffer.length; i++) { - final char ch = buffer[i]; - if (isDelimiter(ch, delimiters)) { - uncapitalizeNext = true; - } else if (uncapitalizeNext) { - buffer[i] = Character.toLowerCase(ch); - uncapitalizeNext = false; - } - } - return new String(buffer); - } - - // ----------------------------------------------------------------------- - /** - *

- * Swaps the case of a String using a word based algorithm. - *

- * - *
    - *
  • Upper case character converts to Lower case
  • - *
  • Title case character converts to Lower case
  • - *
  • Lower case character after Whitespace or at start converts to Title - * case
  • - *
  • Other Lower case character converts to Upper case
  • - *
- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null} - * input String returns {@code null}. - *

- * - *
-	 * StringUtils.swapCase(null)                 = null
-	 * StringUtils.swapCase("")                   = ""
-	 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
-	 * 
- * - * @param str the String to swap case, may be null - * @return the changed String, {@code null} if null String input - */ - public static String swapCase(final String str) { - if (StringUtils.isEmpty(str)) { - return str; - } - final char[] buffer = str.toCharArray(); - - boolean whitespace = true; - - for (int i = 0; i < buffer.length; i++) { - final char ch = buffer[i]; - if (Character.isUpperCase(ch) || Character.isTitleCase(ch)) { - buffer[i] = Character.toLowerCase(ch); - whitespace = false; - } else if (Character.isLowerCase(ch)) { - if (whitespace) { - buffer[i] = Character.toTitleCase(ch); - whitespace = false; - } else { - buffer[i] = Character.toUpperCase(ch); - } - } else { - whitespace = Character.isWhitespace(ch); - } - } - return new String(buffer); - } - - // ----------------------------------------------------------------------- - /** - *

- * Extracts the initial characters from each word in the String. - *

- * - *

- * All first characters after whitespace are returned as a new string. Their - * case is not changed. - *

- * - *

- * Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null} - * input String returns {@code null}. - *

- * - *
-	 * WordUtils.initials(null)             = null
-	 * WordUtils.initials("")               = ""
-	 * WordUtils.initials("Ben John Lee")   = "BJL"
-	 * WordUtils.initials("Ben J.Lee")      = "BJ"
-	 * 
- * - * @param str the String to get initials from, may be null - * @return String of initial letters, {@code null} if null String input - * @see #initials(String,char[]) - * @since 2.2 - */ - public static String initials(final String str) { - return initials(str, null); - } - - /** - *

- * Extracts the initial characters from each word in the String. - *

- * - *

- * All first characters after the defined delimiters are returned as a new - * string. Their case is not changed. - *

- * - *

- * If the delimiters array is null, then Whitespace is used. Whitespace is - * defined by {@link Character#isWhitespace(char)}. A {@code null} input String - * returns {@code null}. An empty delimiter array returns an empty String. - *

- * - *
-	 * WordUtils.initials(null, *)                = null
-	 * WordUtils.initials("", *)                  = ""
-	 * WordUtils.initials("Ben John Lee", null)   = "BJL"
-	 * WordUtils.initials("Ben J.Lee", null)      = "BJ"
-	 * WordUtils.initials("Ben J.Lee", [' ','.']) = "BJL"
-	 * WordUtils.initials(*, new char[0])         = ""
-	 * 
- * - * @param str the String to get initials from, may be null - * @param delimiters set of characters to determine words, null means whitespace - * @return String of initial characters, {@code null} if null String input - * @see #initials(String) - * @since 2.2 - */ - public static String initials(final String str, final char... delimiters) { - if (StringUtils.isEmpty(str)) { - return str; - } - if (delimiters != null && delimiters.length == 0) { - return StringUtils.EMPTY; - } - final int strLen = str.length(); - final char[] buf = new char[strLen / 2 + 1]; - int count = 0; - boolean lastWasGap = true; - for (int i = 0; i < strLen; i++) { - final char ch = str.charAt(i); - - if (isDelimiter(ch, delimiters)) { - lastWasGap = true; - } else if (lastWasGap) { - buf[count++] = ch; - lastWasGap = false; - } else { - continue; // ignore ch - } - } - return new String(buf, 0, count); - } - - // ----------------------------------------------------------------------- - /** - *

- * Checks if the String contains all words in the given array. - *

- * - *

- * A {@code null} String will return {@code false}. A {@code null}, zero length - * search array or if one element of array is null will return {@code false}. - *

- * - *
-	 * WordUtils.containsAllWords(null, *)            = false
-	 * WordUtils.containsAllWords("", *)              = false
-	 * WordUtils.containsAllWords(*, null)            = false
-	 * WordUtils.containsAllWords(*, [])              = false
-	 * WordUtils.containsAllWords("abcd", "ab", "cd") = false
-	 * WordUtils.containsAllWords("abc def", "def", "abc") = true
-	 * 
- * - * - * @param word The CharSequence to check, may be null - * @param words The array of String words to search for, may be null - * @return {@code true} if all search words are found, {@code false} otherwise - * @since 3.5 - */ - public static boolean containsAllWords(final CharSequence word, final CharSequence... words) { - if (StringUtils.isEmpty(word) || words.length == 0) { - return false; - } - for (final CharSequence w : words) { - if (StringUtils.isBlank(w)) { - return false; - } - final Pattern p = Pattern.compile(".*\\b" + w + "\\b.*"); - if (!p.matcher(word).matches()) { - return false; - } - } - return true; - } - - // ----------------------------------------------------------------------- - /** - * Is the character a delimiter. - * - * @param ch the character to check - * @param delimiters the delimiters - * @return true if it is a delimiter - */ - private static boolean isDelimiter(final char ch, final char[] delimiters) { - if (delimiters == null) { - return Character.isWhitespace(ch); - } - for (final char delimiter : delimiters) { - if (ch == delimiter) { - return true; - } - } - return false; - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/package-info.java b/sources/main/java/org/apache/commons/lang3/text/package-info.java deleted file mode 100644 index fbc58e2a..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/package-info.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - *

- * Provides classes for handling and manipulating text, partly as an extension - * to {@link java.text}. The classes in this package are, for the most part, - * intended to be instantiated (i.e. they are not utility classes with lots of - * static methods). - *

- * - *

- * Amongst other classes, the text package provides a replacement for - * {@link java.lang.StringBuffer} named - * {@link org.apache.commons.lang3.text.StrBuilder}, a class for substituting - * variables within a String named - * {@link org.apache.commons.lang3.text.StrSubstitutor} and a replacement for - * {@link java.util.StringTokenizer} named - * {@link org.apache.commons.lang3.text.StrTokenizer}. While somewhat ungainly, - * the {@code Str} prefix has been used to ensure we don't clash with any - * current or future standard Java classes. - *

- * - * @since 2.1 - */ -package org.apache.commons.lang3.text; diff --git a/sources/main/java/org/apache/commons/lang3/text/translate/AggregateTranslator.java b/sources/main/java/org/apache/commons/lang3/text/translate/AggregateTranslator.java deleted file mode 100644 index 829a01f2..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/translate/AggregateTranslator.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text.translate; - -import java.io.IOException; -import java.io.Writer; - -/** - * Executes a sequence of translators one after the other. Execution ends - * whenever the first translator consumes codepoints from the input. - * - * @since 3.0 - * @version $Id: AggregateTranslator.java 1436770 2013-01-22 07:09:45Z ggregory - * $ - */ -public class AggregateTranslator extends CharSequenceTranslator { - - private final CharSequenceTranslator[] translators; - - /** - * Specify the translators to be used at creation time. - * - * @param translators CharSequenceTranslator array to aggregate - */ - public AggregateTranslator(final CharSequenceTranslator... translators) { - this.translators = new CharSequenceTranslator[translators.length]; - System.arraycopy(translators, 0, this.translators, 0, translators.length); - } - - /** - * The first translator to consume codepoints from the input is the 'winner'. - * Execution stops with the number of consumed codepoints being returned. - * {@inheritDoc} - */ - @Override - public int translate(final CharSequence input, final int index, final Writer out) throws IOException { - for (final CharSequenceTranslator translator : translators) { - final int consumed = translator.translate(input, index, out); - if (consumed != 0) { - return consumed; - } - } - return 0; - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java b/sources/main/java/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java deleted file mode 100644 index cec33dc6..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text.translate; - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.util.Locale; - -/** - * An API for translating text. Its core use is to escape and unescape text. - * Because escaping and unescaping is completely contextual, the API does not - * present two separate signatures. - * - * @since 3.0 - * @version $Id: CharSequenceTranslator.java 1568612 2014-02-15 10:35:35Z - * britter $ - */ -public abstract class CharSequenceTranslator { - - /** - * Translate a set of codepoints, represented by an int index into a - * CharSequence, into another set of codepoints. The number of codepoints - * consumed must be returned, and the only IOExceptions thrown must be from - * interacting with the Writer so that the top level API may reliably ignore - * StringWriter IOExceptions. - * - * @param input CharSequence that is being translated - * @param index int representing the current point of translation - * @param out Writer to translate the text to - * @return int count of codepoints consumed - * @throws IOException if and only if the Writer produces an IOException - */ - public abstract int translate(CharSequence input, int index, Writer out) throws IOException; - - /** - * Helper for non-Writer usage. - * - * @param input CharSequence to be translated - * @return String output of translation - */ - public final String translate(final CharSequence input) { - if (input == null) { - return null; - } - try { - final StringWriter writer = new StringWriter(input.length() * 2); - translate(input, writer); - return writer.toString(); - } catch (final IOException ioe) { - // this should never ever happen while writing to a StringWriter - throw new RuntimeException(ioe); - } - } - - /** - * Translate an input onto a Writer. This is intentionally final as its - * algorithm is tightly coupled with the abstract method of this class. - * - * @param input CharSequence that is being translated - * @param out Writer to translate the text to - * @throws IOException if and only if the Writer produces an IOException - */ - public final void translate(final CharSequence input, final Writer out) throws IOException { - if (out == null) { - throw new IllegalArgumentException("The Writer must not be null"); - } - if (input == null) { - return; - } - int pos = 0; - final int len = input.length(); - while (pos < len) { - final int consumed = translate(input, pos, out); - if (consumed == 0) { - final char[] c = Character.toChars(Character.codePointAt(input, pos)); - out.write(c); - pos += c.length; - continue; - } - // contract with translators is that they have to understand codepoints - // and they just took care of a surrogate pair - for (int pt = 0; pt < consumed; pt++) { - pos += Character.charCount(Character.codePointAt(input, pos)); - } - } - } - - /** - * Helper method to create a merger of this translator with another set of - * translators. Useful in customizing the standard functionality. - * - * @param translators CharSequenceTranslator array of translators to merge with - * this one - * @return CharSequenceTranslator merging this translator with the others - */ - public final CharSequenceTranslator with(final CharSequenceTranslator... translators) { - final CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1]; - newArray[0] = this; - System.arraycopy(translators, 0, newArray, 1, translators.length); - return new AggregateTranslator(newArray); - } - - /** - *

- * Returns an upper case hexadecimal String for the given - * character. - *

- * - * @param codepoint The codepoint to convert. - * @return An upper case hexadecimal String - */ - public static String hex(final int codepoint) { - return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/translate/CodePointTranslator.java b/sources/main/java/org/apache/commons/lang3/text/translate/CodePointTranslator.java deleted file mode 100644 index a9567293..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/translate/CodePointTranslator.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text.translate; - -import java.io.IOException; -import java.io.Writer; - -/** - * Helper subclass to CharSequenceTranslator to allow for translations that will - * replace up to one character at a time. - * - * @since 3.0 - * @version $Id: CodePointTranslator.java 1553931 2013-12-28 21:24:44Z ggregory - * $ - */ -public abstract class CodePointTranslator extends CharSequenceTranslator { - - /** - * Implementation of translate that maps onto the abstract translate(int, - * Writer) method. {@inheritDoc} - */ - @Override - public final int translate(final CharSequence input, final int index, final Writer out) throws IOException { - final int codepoint = Character.codePointAt(input, index); - final boolean consumed = translate(codepoint, out); - return consumed ? 1 : 0; - } - - /** - * Translate the specified codepoint into another. - * - * @param codepoint int character input to translate - * @param out Writer to optionally push the translated output to - * @return boolean as to whether translation occurred or not - * @throws IOException if and only if the Writer produces an IOException - */ - public abstract boolean translate(int codepoint, Writer out) throws IOException; - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/translate/EntityArrays.java b/sources/main/java/org/apache/commons/lang3/text/translate/EntityArrays.java deleted file mode 100644 index 20626cea..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/translate/EntityArrays.java +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text.translate; - -/** - * Class holding various entity data for HTML and XML - generally for use with - * the LookupTranslator. All arrays are of length [*][2]. - * - * @since 3.0 - * @version $Id: EntityArrays.java 1436770 2013-01-22 07:09:45Z ggregory $ - */ -public class EntityArrays { - - /** - * Mapping to escape ISO-8859-1 - * characters to their named HTML 3.x equivalents. - * - * @return the mapping table - */ - public static String[][] ISO8859_1_ESCAPE() { - return ISO8859_1_ESCAPE.clone(); - } - - private static final String[][] ISO8859_1_ESCAPE = { { "\u00A0", " " }, // non-breaking space - { "\u00A1", "¡" }, // inverted exclamation mark - { "\u00A2", "¢" }, // cent sign - { "\u00A3", "£" }, // pound sign - { "\u00A4", "¤" }, // currency sign - { "\u00A5", "¥" }, // yen sign = yuan sign - { "\u00A6", "¦" }, // broken bar = broken vertical bar - { "\u00A7", "§" }, // section sign - { "\u00A8", "¨" }, // diaeresis = spacing diaeresis - { "\u00A9", "©" }, // � - copyright sign - { "\u00AA", "ª" }, // feminine ordinal indicator - { "\u00AB", "«" }, // left-pointing double angle quotation mark = left pointing guillemet - { "\u00AC", "¬" }, // not sign - { "\u00AD", "­" }, // soft hyphen = discretionary hyphen - { "\u00AE", "®" }, // � - registered trademark sign - { "\u00AF", "¯" }, // macron = spacing macron = overline = APL overbar - { "\u00B0", "°" }, // degree sign - { "\u00B1", "±" }, // plus-minus sign = plus-or-minus sign - { "\u00B2", "²" }, // superscript two = superscript digit two = squared - { "\u00B3", "³" }, // superscript three = superscript digit three = cubed - { "\u00B4", "´" }, // acute accent = spacing acute - { "\u00B5", "µ" }, // micro sign - { "\u00B6", "¶" }, // pilcrow sign = paragraph sign - { "\u00B7", "·" }, // middle dot = Georgian comma = Greek middle dot - { "\u00B8", "¸" }, // cedilla = spacing cedilla - { "\u00B9", "¹" }, // superscript one = superscript digit one - { "\u00BA", "º" }, // masculine ordinal indicator - { "\u00BB", "»" }, // right-pointing double angle quotation mark = right pointing guillemet - { "\u00BC", "¼" }, // vulgar fraction one quarter = fraction one quarter - { "\u00BD", "½" }, // vulgar fraction one half = fraction one half - { "\u00BE", "¾" }, // vulgar fraction three quarters = fraction three quarters - { "\u00BF", "¿" }, // inverted question mark = turned question mark - { "\u00C0", "À" }, // � - uppercase A, grave accent - { "\u00C1", "Á" }, // � - uppercase A, acute accent - { "\u00C2", "Â" }, // � - uppercase A, circumflex accent - { "\u00C3", "Ã" }, // � - uppercase A, tilde - { "\u00C4", "Ä" }, // � - uppercase A, umlaut - { "\u00C5", "Å" }, // � - uppercase A, ring - { "\u00C6", "Æ" }, // � - uppercase AE - { "\u00C7", "Ç" }, // � - uppercase C, cedilla - { "\u00C8", "È" }, // � - uppercase E, grave accent - { "\u00C9", "É" }, // � - uppercase E, acute accent - { "\u00CA", "Ê" }, // � - uppercase E, circumflex accent - { "\u00CB", "Ë" }, // � - uppercase E, umlaut - { "\u00CC", "Ì" }, // � - uppercase I, grave accent - { "\u00CD", "Í" }, // � - uppercase I, acute accent - { "\u00CE", "Î" }, // � - uppercase I, circumflex accent - { "\u00CF", "Ï" }, // � - uppercase I, umlaut - { "\u00D0", "Ð" }, // � - uppercase Eth, Icelandic - { "\u00D1", "Ñ" }, // � - uppercase N, tilde - { "\u00D2", "Ò" }, // � - uppercase O, grave accent - { "\u00D3", "Ó" }, // � - uppercase O, acute accent - { "\u00D4", "Ô" }, // � - uppercase O, circumflex accent - { "\u00D5", "Õ" }, // � - uppercase O, tilde - { "\u00D6", "Ö" }, // � - uppercase O, umlaut - { "\u00D7", "×" }, // multiplication sign - { "\u00D8", "Ø" }, // � - uppercase O, slash - { "\u00D9", "Ù" }, // � - uppercase U, grave accent - { "\u00DA", "Ú" }, // � - uppercase U, acute accent - { "\u00DB", "Û" }, // � - uppercase U, circumflex accent - { "\u00DC", "Ü" }, // � - uppercase U, umlaut - { "\u00DD", "Ý" }, // � - uppercase Y, acute accent - { "\u00DE", "Þ" }, // � - uppercase THORN, Icelandic - { "\u00DF", "ß" }, // � - lowercase sharps, German - { "\u00E0", "à" }, // � - lowercase a, grave accent - { "\u00E1", "á" }, // � - lowercase a, acute accent - { "\u00E2", "â" }, // � - lowercase a, circumflex accent - { "\u00E3", "ã" }, // � - lowercase a, tilde - { "\u00E4", "ä" }, // � - lowercase a, umlaut - { "\u00E5", "å" }, // � - lowercase a, ring - { "\u00E6", "æ" }, // � - lowercase ae - { "\u00E7", "ç" }, // � - lowercase c, cedilla - { "\u00E8", "è" }, // � - lowercase e, grave accent - { "\u00E9", "é" }, // � - lowercase e, acute accent - { "\u00EA", "ê" }, // � - lowercase e, circumflex accent - { "\u00EB", "ë" }, // � - lowercase e, umlaut - { "\u00EC", "ì" }, // � - lowercase i, grave accent - { "\u00ED", "í" }, // � - lowercase i, acute accent - { "\u00EE", "î" }, // � - lowercase i, circumflex accent - { "\u00EF", "ï" }, // � - lowercase i, umlaut - { "\u00F0", "ð" }, // � - lowercase eth, Icelandic - { "\u00F1", "ñ" }, // � - lowercase n, tilde - { "\u00F2", "ò" }, // � - lowercase o, grave accent - { "\u00F3", "ó" }, // � - lowercase o, acute accent - { "\u00F4", "ô" }, // � - lowercase o, circumflex accent - { "\u00F5", "õ" }, // � - lowercase o, tilde - { "\u00F6", "ö" }, // � - lowercase o, umlaut - { "\u00F7", "÷" }, // division sign - { "\u00F8", "ø" }, // � - lowercase o, slash - { "\u00F9", "ù" }, // � - lowercase u, grave accent - { "\u00FA", "ú" }, // � - lowercase u, acute accent - { "\u00FB", "û" }, // � - lowercase u, circumflex accent - { "\u00FC", "ü" }, // � - lowercase u, umlaut - { "\u00FD", "ý" }, // � - lowercase y, acute accent - { "\u00FE", "þ" }, // � - lowercase thorn, Icelandic - { "\u00FF", "ÿ" }, // � - lowercase y, umlaut - }; - - /** - * Reverse of {@link #ISO8859_1_ESCAPE()} for unescaping purposes. - * - * @return the mapping table - */ - public static String[][] ISO8859_1_UNESCAPE() { - return ISO8859_1_UNESCAPE.clone(); - } - - private static final String[][] ISO8859_1_UNESCAPE = invert(ISO8859_1_ESCAPE); - - /** - * Mapping to escape additional - * character entity - * references. Note that this must be used with {@link #ISO8859_1_ESCAPE()} - * to get the full list of HTML 4.0 character entities. - * - * @return the mapping table - */ - public static String[][] HTML40_EXTENDED_ESCAPE() { - return HTML40_EXTENDED_ESCAPE.clone(); - } - - private static final String[][] HTML40_EXTENDED_ESCAPE = { - // - { "\u0192", "ƒ" }, // latin small f with hook = function= florin, U+0192 ISOtech --> - // - { "\u0391", "Α" }, // greek capital letter alpha, U+0391 --> - { "\u0392", "Β" }, // greek capital letter beta, U+0392 --> - { "\u0393", "Γ" }, // greek capital letter gamma,U+0393 ISOgrk3 --> - { "\u0394", "Δ" }, // greek capital letter delta,U+0394 ISOgrk3 --> - { "\u0395", "Ε" }, // greek capital letter epsilon, U+0395 --> - { "\u0396", "Ζ" }, // greek capital letter zeta, U+0396 --> - { "\u0397", "Η" }, // greek capital letter eta, U+0397 --> - { "\u0398", "Θ" }, // greek capital letter theta,U+0398 ISOgrk3 --> - { "\u0399", "Ι" }, // greek capital letter iota, U+0399 --> - { "\u039A", "Κ" }, // greek capital letter kappa, U+039A --> - { "\u039B", "Λ" }, // greek capital letter lambda,U+039B ISOgrk3 --> - { "\u039C", "Μ" }, // greek capital letter mu, U+039C --> - { "\u039D", "Ν" }, // greek capital letter nu, U+039D --> - { "\u039E", "Ξ" }, // greek capital letter xi, U+039E ISOgrk3 --> - { "\u039F", "Ο" }, // greek capital letter omicron, U+039F --> - { "\u03A0", "Π" }, // greek capital letter pi, U+03A0 ISOgrk3 --> - { "\u03A1", "Ρ" }, // greek capital letter rho, U+03A1 --> - // - { "\u03A3", "Σ" }, // greek capital letter sigma,U+03A3 ISOgrk3 --> - { "\u03A4", "Τ" }, // greek capital letter tau, U+03A4 --> - { "\u03A5", "Υ" }, // greek capital letter upsilon,U+03A5 ISOgrk3 --> - { "\u03A6", "Φ" }, // greek capital letter phi,U+03A6 ISOgrk3 --> - { "\u03A7", "Χ" }, // greek capital letter chi, U+03A7 --> - { "\u03A8", "Ψ" }, // greek capital letter psi,U+03A8 ISOgrk3 --> - { "\u03A9", "Ω" }, // greek capital letter omega,U+03A9 ISOgrk3 --> - { "\u03B1", "α" }, // greek small letter alpha,U+03B1 ISOgrk3 --> - { "\u03B2", "β" }, // greek small letter beta, U+03B2 ISOgrk3 --> - { "\u03B3", "γ" }, // greek small letter gamma,U+03B3 ISOgrk3 --> - { "\u03B4", "δ" }, // greek small letter delta,U+03B4 ISOgrk3 --> - { "\u03B5", "ε" }, // greek small letter epsilon,U+03B5 ISOgrk3 --> - { "\u03B6", "ζ" }, // greek small letter zeta, U+03B6 ISOgrk3 --> - { "\u03B7", "η" }, // greek small letter eta, U+03B7 ISOgrk3 --> - { "\u03B8", "θ" }, // greek small letter theta,U+03B8 ISOgrk3 --> - { "\u03B9", "ι" }, // greek small letter iota, U+03B9 ISOgrk3 --> - { "\u03BA", "κ" }, // greek small letter kappa,U+03BA ISOgrk3 --> - { "\u03BB", "λ" }, // greek small letter lambda,U+03BB ISOgrk3 --> - { "\u03BC", "μ" }, // greek small letter mu, U+03BC ISOgrk3 --> - { "\u03BD", "ν" }, // greek small letter nu, U+03BD ISOgrk3 --> - { "\u03BE", "ξ" }, // greek small letter xi, U+03BE ISOgrk3 --> - { "\u03BF", "ο" }, // greek small letter omicron, U+03BF NEW --> - { "\u03C0", "π" }, // greek small letter pi, U+03C0 ISOgrk3 --> - { "\u03C1", "ρ" }, // greek small letter rho, U+03C1 ISOgrk3 --> - { "\u03C2", "ς" }, // greek small letter final sigma,U+03C2 ISOgrk3 --> - { "\u03C3", "σ" }, // greek small letter sigma,U+03C3 ISOgrk3 --> - { "\u03C4", "τ" }, // greek small letter tau, U+03C4 ISOgrk3 --> - { "\u03C5", "υ" }, // greek small letter upsilon,U+03C5 ISOgrk3 --> - { "\u03C6", "φ" }, // greek small letter phi, U+03C6 ISOgrk3 --> - { "\u03C7", "χ" }, // greek small letter chi, U+03C7 ISOgrk3 --> - { "\u03C8", "ψ" }, // greek small letter psi, U+03C8 ISOgrk3 --> - { "\u03C9", "ω" }, // greek small letter omega,U+03C9 ISOgrk3 --> - { "\u03D1", "ϑ" }, // greek small letter theta symbol,U+03D1 NEW --> - { "\u03D2", "ϒ" }, // greek upsilon with hook symbol,U+03D2 NEW --> - { "\u03D6", "ϖ" }, // greek pi symbol, U+03D6 ISOgrk3 --> - // - { "\u2022", "•" }, // bullet = black small circle,U+2022 ISOpub --> - // - { "\u2026", "…" }, // horizontal ellipsis = three dot leader,U+2026 ISOpub --> - { "\u2032", "′" }, // prime = minutes = feet, U+2032 ISOtech --> - { "\u2033", "″" }, // double prime = seconds = inches,U+2033 ISOtech --> - { "\u203E", "‾" }, // overline = spacing overscore,U+203E NEW --> - { "\u2044", "⁄" }, // fraction slash, U+2044 NEW --> - // - { "\u2118", "℘" }, // script capital P = power set= Weierstrass p, U+2118 ISOamso --> - { "\u2111", "ℑ" }, // blackletter capital I = imaginary part,U+2111 ISOamso --> - { "\u211C", "ℜ" }, // blackletter capital R = real part symbol,U+211C ISOamso --> - { "\u2122", "™" }, // trade mark sign, U+2122 ISOnum --> - { "\u2135", "ℵ" }, // alef symbol = first transfinite cardinal,U+2135 NEW --> - // - // - { "\u2190", "←" }, // leftwards arrow, U+2190 ISOnum --> - { "\u2191", "↑" }, // upwards arrow, U+2191 ISOnum--> - { "\u2192", "→" }, // rightwards arrow, U+2192 ISOnum --> - { "\u2193", "↓" }, // downwards arrow, U+2193 ISOnum --> - { "\u2194", "↔" }, // left right arrow, U+2194 ISOamsa --> - { "\u21B5", "↵" }, // downwards arrow with corner leftwards= carriage return, U+21B5 NEW --> - { "\u21D0", "⇐" }, // leftwards double arrow, U+21D0 ISOtech --> - // - { "\u21D1", "⇑" }, // upwards double arrow, U+21D1 ISOamsa --> - { "\u21D2", "⇒" }, // rightwards double arrow,U+21D2 ISOtech --> - // - { "\u21D3", "⇓" }, // downwards double arrow, U+21D3 ISOamsa --> - { "\u21D4", "⇔" }, // left right double arrow,U+21D4 ISOamsa --> - // - { "\u2200", "∀" }, // for all, U+2200 ISOtech --> - { "\u2202", "∂" }, // partial differential, U+2202 ISOtech --> - { "\u2203", "∃" }, // there exists, U+2203 ISOtech --> - { "\u2205", "∅" }, // empty set = null set = diameter,U+2205 ISOamso --> - { "\u2207", "∇" }, // nabla = backward difference,U+2207 ISOtech --> - { "\u2208", "∈" }, // element of, U+2208 ISOtech --> - { "\u2209", "∉" }, // not an element of, U+2209 ISOtech --> - { "\u220B", "∋" }, // contains as member, U+220B ISOtech --> - // - { "\u220F", "∏" }, // n-ary product = product sign,U+220F ISOamsb --> - // - { "\u2211", "∑" }, // n-ary summation, U+2211 ISOamsb --> - // - { "\u2212", "−" }, // minus sign, U+2212 ISOtech --> - { "\u2217", "∗" }, // asterisk operator, U+2217 ISOtech --> - { "\u221A", "√" }, // square root = radical sign,U+221A ISOtech --> - { "\u221D", "∝" }, // proportional to, U+221D ISOtech --> - { "\u221E", "∞" }, // infinity, U+221E ISOtech --> - { "\u2220", "∠" }, // angle, U+2220 ISOamso --> - { "\u2227", "∧" }, // logical and = wedge, U+2227 ISOtech --> - { "\u2228", "∨" }, // logical or = vee, U+2228 ISOtech --> - { "\u2229", "∩" }, // intersection = cap, U+2229 ISOtech --> - { "\u222A", "∪" }, // union = cup, U+222A ISOtech --> - { "\u222B", "∫" }, // integral, U+222B ISOtech --> - { "\u2234", "∴" }, // therefore, U+2234 ISOtech --> - { "\u223C", "∼" }, // tilde operator = varies with = similar to,U+223C ISOtech --> - // - { "\u2245", "≅" }, // approximately equal to, U+2245 ISOtech --> - { "\u2248", "≈" }, // almost equal to = asymptotic to,U+2248 ISOamsr --> - { "\u2260", "≠" }, // not equal to, U+2260 ISOtech --> - { "\u2261", "≡" }, // identical to, U+2261 ISOtech --> - { "\u2264", "≤" }, // less-than or equal to, U+2264 ISOtech --> - { "\u2265", "≥" }, // greater-than or equal to,U+2265 ISOtech --> - { "\u2282", "⊂" }, // subset of, U+2282 ISOtech --> - { "\u2283", "⊃" }, // superset of, U+2283 ISOtech --> - // - { "\u2286", "⊆" }, // subset of or equal to, U+2286 ISOtech --> - { "\u2287", "⊇" }, // superset of or equal to,U+2287 ISOtech --> - { "\u2295", "⊕" }, // circled plus = direct sum,U+2295 ISOamsb --> - { "\u2297", "⊗" }, // circled times = vector product,U+2297 ISOamsb --> - { "\u22A5", "⊥" }, // up tack = orthogonal to = perpendicular,U+22A5 ISOtech --> - { "\u22C5", "⋅" }, // dot operator, U+22C5 ISOamsb --> - // - // - { "\u2308", "⌈" }, // left ceiling = apl upstile,U+2308 ISOamsc --> - { "\u2309", "⌉" }, // right ceiling, U+2309 ISOamsc --> - { "\u230A", "⌊" }, // left floor = apl downstile,U+230A ISOamsc --> - { "\u230B", "⌋" }, // right floor, U+230B ISOamsc --> - { "\u2329", "⟨" }, // left-pointing angle bracket = bra,U+2329 ISOtech --> - // - { "\u232A", "⟩" }, // right-pointing angle bracket = ket,U+232A ISOtech --> - // - // - { "\u25CA", "◊" }, // lozenge, U+25CA ISOpub --> - // - { "\u2660", "♠" }, // black spade suit, U+2660 ISOpub --> - // - { "\u2663", "♣" }, // black club suit = shamrock,U+2663 ISOpub --> - { "\u2665", "♥" }, // black heart suit = valentine,U+2665 ISOpub --> - { "\u2666", "♦" }, // black diamond suit, U+2666 ISOpub --> - - // - { "\u0152", "Œ" }, // -- latin capital ligature OE,U+0152 ISOlat2 --> - { "\u0153", "œ" }, // -- latin small ligature oe, U+0153 ISOlat2 --> - // - { "\u0160", "Š" }, // -- latin capital letter S with caron,U+0160 ISOlat2 --> - { "\u0161", "š" }, // -- latin small letter s with caron,U+0161 ISOlat2 --> - { "\u0178", "Ÿ" }, // -- latin capital letter Y with diaeresis,U+0178 ISOlat2 --> - // - { "\u02C6", "ˆ" }, // -- modifier letter circumflex accent,U+02C6 ISOpub --> - { "\u02DC", "˜" }, // small tilde, U+02DC ISOdia --> - // - { "\u2002", " " }, // en space, U+2002 ISOpub --> - { "\u2003", " " }, // em space, U+2003 ISOpub --> - { "\u2009", " " }, // thin space, U+2009 ISOpub --> - { "\u200C", "‌" }, // zero width non-joiner,U+200C NEW RFC 2070 --> - { "\u200D", "‍" }, // zero width joiner, U+200D NEW RFC 2070 --> - { "\u200E", "‎" }, // left-to-right mark, U+200E NEW RFC 2070 --> - { "\u200F", "‏" }, // right-to-left mark, U+200F NEW RFC 2070 --> - { "\u2013", "–" }, // en dash, U+2013 ISOpub --> - { "\u2014", "—" }, // em dash, U+2014 ISOpub --> - { "\u2018", "‘" }, // left single quotation mark,U+2018 ISOnum --> - { "\u2019", "’" }, // right single quotation mark,U+2019 ISOnum --> - { "\u201A", "‚" }, // single low-9 quotation mark, U+201A NEW --> - { "\u201C", "“" }, // left double quotation mark,U+201C ISOnum --> - { "\u201D", "”" }, // right double quotation mark,U+201D ISOnum --> - { "\u201E", "„" }, // double low-9 quotation mark, U+201E NEW --> - { "\u2020", "†" }, // dagger, U+2020 ISOpub --> - { "\u2021", "‡" }, // double dagger, U+2021 ISOpub --> - { "\u2030", "‰" }, // per mille sign, U+2030 ISOtech --> - { "\u2039", "‹" }, // single left-pointing angle quotation mark,U+2039 ISO proposed --> - // - { "\u203A", "›" }, // single right-pointing angle quotation mark,U+203A ISO proposed --> - // - { "\u20AC", "€" }, // -- euro sign, U+20AC NEW --> - }; - - /** - * Reverse of {@link #HTML40_EXTENDED_ESCAPE()} for unescaping purposes. - * - * @return the mapping table - */ - public static String[][] HTML40_EXTENDED_UNESCAPE() { - return HTML40_EXTENDED_UNESCAPE.clone(); - } - - private static final String[][] HTML40_EXTENDED_UNESCAPE = invert(HTML40_EXTENDED_ESCAPE); - - /** - * Mapping to escape the basic XML and HTML character entities. - * - * Namely: {@code " & < >} - * - * @return the mapping table - */ - public static String[][] BASIC_ESCAPE() { - return BASIC_ESCAPE.clone(); - } - - private static final String[][] BASIC_ESCAPE = { { "\"", """ }, // " - double-quote - { "&", "&" }, // & - ampersand - { "<", "<" }, // < - less-than - { ">", ">" }, // > - greater-than - }; - - /** - * Reverse of {@link #BASIC_ESCAPE()} for unescaping purposes. - * - * @return the mapping table - */ - public static String[][] BASIC_UNESCAPE() { - return BASIC_UNESCAPE.clone(); - } - - private static final String[][] BASIC_UNESCAPE = invert(BASIC_ESCAPE); - - /** - * Mapping to escape the apostrophe character to its XML character entity. - * - * @return the mapping table - */ - public static String[][] APOS_ESCAPE() { - return APOS_ESCAPE.clone(); - } - - private static final String[][] APOS_ESCAPE = { { "'", "'" }, // XML apostrophe - }; - - /** - * Reverse of {@link #APOS_ESCAPE()} for unescaping purposes. - * - * @return the mapping table - */ - public static String[][] APOS_UNESCAPE() { - return APOS_UNESCAPE.clone(); - } - - private static final String[][] APOS_UNESCAPE = invert(APOS_ESCAPE); - - /** - * Mapping to escape the Java control characters. - * - * Namely: {@code \b \n \t \f \r} - * - * @return the mapping table - */ - public static String[][] JAVA_CTRL_CHARS_ESCAPE() { - return JAVA_CTRL_CHARS_ESCAPE.clone(); - } - - private static final String[][] JAVA_CTRL_CHARS_ESCAPE = { { "\b", "\\b" }, { "\n", "\\n" }, { "\t", "\\t" }, - { "\f", "\\f" }, { "\r", "\\r" } }; - - /** - * Reverse of {@link #JAVA_CTRL_CHARS_ESCAPE()} for unescaping purposes. - * - * @return the mapping table - */ - public static String[][] JAVA_CTRL_CHARS_UNESCAPE() { - return JAVA_CTRL_CHARS_UNESCAPE.clone(); - } - - private static final String[][] JAVA_CTRL_CHARS_UNESCAPE = invert(JAVA_CTRL_CHARS_ESCAPE); - - /** - * Used to invert an escape array into an unescape array - * - * @param array String[][] to be inverted - * @return String[][] inverted array - */ - public static String[][] invert(final String[][] array) { - final String[][] newarray = new String[array.length][2]; - for (int i = 0; i < array.length; i++) { - newarray[i][0] = array[i][1]; - newarray[i][1] = array[i][0]; - } - return newarray; - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/translate/JavaUnicodeEscaper.java b/sources/main/java/org/apache/commons/lang3/text/translate/JavaUnicodeEscaper.java deleted file mode 100644 index 8944c016..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/translate/JavaUnicodeEscaper.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text.translate; - -/** - * Translates codepoints to their Unicode escaped value suitable for Java - * source. - * - * @since 3.2 - * @version $Id: JavaUnicodeEscaper.java 1451550 2013-03-01 10:06:13Z olamy $ - */ -public class JavaUnicodeEscaper extends UnicodeEscaper { - - /** - *

- * Constructs a JavaUnicodeEscaper above the specified value - * (exclusive). - *

- * - * @param codepoint above which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static JavaUnicodeEscaper above(final int codepoint) { - return outsideOf(0, codepoint); - } - - /** - *

- * Constructs a JavaUnicodeEscaper below the specified value - * (exclusive). - *

- * - * @param codepoint below which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static JavaUnicodeEscaper below(final int codepoint) { - return outsideOf(codepoint, Integer.MAX_VALUE); - } - - /** - *

- * Constructs a JavaUnicodeEscaper between the specified values - * (inclusive). - *

- * - * @param codepointLow above which to escape - * @param codepointHigh below which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static JavaUnicodeEscaper between(final int codepointLow, final int codepointHigh) { - return new JavaUnicodeEscaper(codepointLow, codepointHigh, true); - } - - /** - *

- * Constructs a JavaUnicodeEscaper outside of the specified values - * (exclusive). - *

- * - * @param codepointLow below which to escape - * @param codepointHigh above which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static JavaUnicodeEscaper outsideOf(final int codepointLow, final int codepointHigh) { - return new JavaUnicodeEscaper(codepointLow, codepointHigh, false); - } - - /** - *

- * Constructs a JavaUnicodeEscaper for the specified range. This is - * the underlying method for the other constructors/builders. The - * below and above boundaries are inclusive when - * between is true and exclusive when it is - * false. - *

- * - * @param below int value representing the lowest codepoint boundary - * @param above int value representing the highest codepoint boundary - * @param between whether to escape between the boundaries or outside them - */ - public JavaUnicodeEscaper(final int below, final int above, final boolean between) { - super(below, above, between); - } - - /** - * Converts the given codepoint to a hex string of the form - * {@code "\\uXXXX\\uXXXX"} - * - * @param codepoint a Unicode code point - * @return the hex string for the given codepoint - */ - @Override - protected String toUtf16Escape(final int codepoint) { - final char[] surrogatePair = Character.toChars(codepoint); - return "\\u" + hex(surrogatePair[0]) + "\\u" + hex(surrogatePair[1]); - } - -} diff --git a/sources/main/java/org/apache/commons/lang3/text/translate/LookupTranslator.java b/sources/main/java/org/apache/commons/lang3/text/translate/LookupTranslator.java deleted file mode 100644 index e3c93345..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/translate/LookupTranslator.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text.translate; - -import java.io.IOException; -import java.io.Writer; -import java.util.HashMap; - -/** - * Translates a value using a lookup table. - * - * @since 3.0 - * @version $Id: LookupTranslator.java 1470822 2013-04-23 06:00:41Z bayard $ - */ -public class LookupTranslator extends CharSequenceTranslator { - - private final HashMap lookupMap; - private final int shortest; - private final int longest; - - /** - * Define the lookup table to be used in translation - * - * Note that, as of Lang 3.1, the key to the lookup table is converted to a - * java.lang.String, while the value remains as a java.lang.CharSequence. This - * is because we need the key to support hashCode and equals(Object), allowing - * it to be the key for a HashMap. See LANG-882. - * - * @param lookup CharSequence[][] table of size [*][2] - */ - public LookupTranslator(final CharSequence[]... lookup) { - lookupMap = new HashMap(); - int _shortest = Integer.MAX_VALUE; - int _longest = 0; - if (lookup != null) { - for (final CharSequence[] seq : lookup) { - this.lookupMap.put(seq[0].toString(), seq[1]); - final int sz = seq[0].length(); - if (sz < _shortest) { - _shortest = sz; - } - if (sz > _longest) { - _longest = sz; - } - } - } - shortest = _shortest; - longest = _longest; - } - - /** - * {@inheritDoc} - */ - @Override - public int translate(final CharSequence input, final int index, final Writer out) throws IOException { - int max = longest; - if (index + longest > input.length()) { - max = input.length() - index; - } - // descend so as to get a greedy algorithm - for (int i = max; i >= shortest; i--) { - final CharSequence subSeq = input.subSequence(index, index + i); - final CharSequence result = lookupMap.get(subSeq.toString()); - if (result != null) { - out.write(result.toString()); - return i; - } - } - return 0; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/text/translate/NumericEntityEscaper.java b/sources/main/java/org/apache/commons/lang3/text/translate/NumericEntityEscaper.java deleted file mode 100644 index b216c0c3..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/translate/NumericEntityEscaper.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text.translate; - -import java.io.IOException; -import java.io.Writer; - -/** - * Translates codepoints to their XML numeric entity escaped value. - * - * @since 3.0 - * @version $Id: NumericEntityEscaper.java 1436768 2013-01-22 07:07:42Z ggregory - * $ - */ -public class NumericEntityEscaper extends CodePointTranslator { - - private final int below; - private final int above; - private final boolean between; - - /** - *

- * Constructs a NumericEntityEscaper for the specified range. This - * is the underlying method for the other constructors/builders. The - * below and above boundaries are inclusive when - * between is true and exclusive when it is - * false. - *

- * - * @param below int value representing the lowest codepoint boundary - * @param above int value representing the highest codepoint boundary - * @param between whether to escape between the boundaries or outside them - */ - private NumericEntityEscaper(final int below, final int above, final boolean between) { - this.below = below; - this.above = above; - this.between = between; - } - - /** - *

- * Constructs a NumericEntityEscaper for all characters. - *

- */ - public NumericEntityEscaper() { - this(0, Integer.MAX_VALUE, true); - } - - /** - *

- * Constructs a NumericEntityEscaper below the specified value - * (exclusive). - *

- * - * @param codepoint below which to escape - * @return the newly created {@code NumericEntityEscaper} instance - */ - public static NumericEntityEscaper below(final int codepoint) { - return outsideOf(codepoint, Integer.MAX_VALUE); - } - - /** - *

- * Constructs a NumericEntityEscaper above the specified value - * (exclusive). - *

- * - * @param codepoint above which to escape - * @return the newly created {@code NumericEntityEscaper} instance - */ - public static NumericEntityEscaper above(final int codepoint) { - return outsideOf(0, codepoint); - } - - /** - *

- * Constructs a NumericEntityEscaper between the specified values - * (inclusive). - *

- * - * @param codepointLow above which to escape - * @param codepointHigh below which to escape - * @return the newly created {@code NumericEntityEscaper} instance - */ - public static NumericEntityEscaper between(final int codepointLow, final int codepointHigh) { - return new NumericEntityEscaper(codepointLow, codepointHigh, true); - } - - /** - *

- * Constructs a NumericEntityEscaper outside of the specified - * values (exclusive). - *

- * - * @param codepointLow below which to escape - * @param codepointHigh above which to escape - * @return the newly created {@code NumericEntityEscaper} instance - */ - public static NumericEntityEscaper outsideOf(final int codepointLow, final int codepointHigh) { - return new NumericEntityEscaper(codepointLow, codepointHigh, false); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean translate(final int codepoint, final Writer out) throws IOException { - if (between) { - if (codepoint < below || codepoint > above) { - return false; - } - } else { - if (codepoint >= below && codepoint <= above) { - return false; - } - } - - out.write("&#"); - out.write(Integer.toString(codepoint, 10)); - out.write(';'); - return true; - } -} diff --git a/sources/main/java/org/apache/commons/lang3/text/translate/NumericEntityUnescaper.java b/sources/main/java/org/apache/commons/lang3/text/translate/NumericEntityUnescaper.java deleted file mode 100644 index a6fe2945..00000000 --- a/sources/main/java/org/apache/commons/lang3/text/translate/NumericEntityUnescaper.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.lang3.text.translate; - -import java.io.IOException; -import java.io.Writer; -import java.util.Arrays; -import java.util.EnumSet; - -/** - * Translate XML numeric entities of the form &#[xX]?\d+;? to the specific - * codepoint. - * - * Note that the semi-colon is optional. - * - * @since 3.0 - * @version $Id: NumericEntityUnescaper.java 1583482 2014-03-31 22:54:57Z niallp - * $ - */ -public class NumericEntityUnescaper extends CharSequenceTranslator { - - public static enum OPTION { - semiColonRequired, semiColonOptional, errorIfNoSemiColon - } - - // TODO?: Create an OptionsSet class to hide some of the conditional logic below - private final EnumSet